-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBuffLog.php
More file actions
143 lines (114 loc) · 5.31 KB
/
BuffLog.php
File metadata and controls
143 lines (114 loc) · 5.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
<?php
namespace Buffer\Bufflog;
use Monolog\Logger as Logger;
use Monolog\Handler\StreamHandler;
class BuffLog {
protected static $instance;
private static $logger = null;
// default verbosity starting at this level
private static $verbosityLevel = Logger::NOTICE;
// verbosity can be changed with setting this env var
public static $logLevelEnvVar = "LOG_LEVEL";
public static $isDebug = false;
public static $debugKey = "debug";
public static $debugValue = "";
// we can use strtolower(Logger::getLevels()) instead
private static $logOutputMethods = ['debug', 'info', 'notice', 'warning', 'error', 'critical'];
private static $extraAllowedMethods = ['getName', 'pushHandler', 'setHandlers', 'getHandlers', 'pushProcessor', 'getProcessors', 'getLevels'];
/**
* Method to return the Monolog instance
*
* @return \Monolog\Logger
*/
static public function getLogger()
{
if (! self::$instance) {
self::configureInstance();
}
return self::$instance;
}
protected static function configureInstance()
{
if (!class_exists("\DDTrace\GlobalTracer")) {
error_log("Tip #1: Can't find \DDTrace\GlobalTracer class. Did you install the Datadog APM tracer extension? It will allow you to have logs enriched with traces making troubleshooting easier! :)");
error_log("Tip #2: If you run a cli mode service (such as a worker), did you set the DD_TRACE_CLI_ENABLED env variable?");
}
// @TODO: We could potentially use the Kubernetes downward API to
// define the logger name. This will make it easier for developers
// to read and friendlier to identify where come the logs at a glance
$logger = new Logger('php-bufflog');
$logLevelFromEnv = getenv(self::$logLevelEnvVar);
$monologLevels = $logger->getLevels();
if ($logLevelFromEnv) {
// only if the level exists, we change the verbosity level
if (key_exists($logLevelFromEnv, $monologLevels)) {
self::$verbosityLevel = $monologLevels[$logLevelFromEnv];
} else {
error_log(self::$logLevelEnvVar . "={$logLevelFromEnv} verbosity level does not exists. Please use: " . implode(', ', array_keys($monologLevels)));
}
}
self::checkDebug();
$handler = new StreamHandler('php://stdout', self::$verbosityLevel);
$handler->setFormatter( new \Monolog\Formatter\JsonFormatter() );
$logger->pushHandler($handler);
self::$instance = $logger;
}
// This will be called when a static method in the class doesn't exists
public static function __callStatic($methodName, $args)
{
if (method_exists(self::getLogger(), $methodName)) {
if (in_array($methodName, array_merge(self::$logOutputMethods, self::$extraAllowedMethods))) {
if (in_array($methodName, self::$logOutputMethods)) {
self::enrichLog();
}
// Where the magic happen. We "proxy" functions name with arguments to the Monolog instance
return call_user_func_array(array(self::getLogger(), $methodName), $args);
} else {
error_log("BuffLog::$methodName() is not supported yet. Add it to the BuffLog whitelist to allow it");
}
} else {
error_log("BuffLog::$methodName() method does not exist");
}
}
private static function checkDebug()
{
if (is_array($_GET) && isset($_GET[self::$debugKey])) {
self::$isDebug = true;
// we set the lowest level of logs to see everything
self::$verbosityLevel = Logger::DEBUG;
self::$debugValue = $_GET[self::$debugKey];
return true;
}
return false;
}
private static function enrichLog()
{
// We should probably implement this as a Monolog Processor
// https://github.com/Seldaek/monolog/tree/master/src/Monolog/Processor
self::getLogger()->pushProcessor(function ($record) {
// We should grab any Buffer information useful when available
// Need to check with the Core team: accountID / userID / profileID
// $user = Buffer/Core::getCurrentUser();
// That should look like:
// $record['context']['user'] = array(
// 'accountID' => $user->getAccountID(),
// 'userID' => $user->getUserID(),
// 'profileID' => $user->getProfileID()
// );
try {
// Add traces information to be able to correlate logs with APM
$ddTraceSpan = \DDTrace\GlobalTracer::get()->getActiveSpan();
$record['context']['dd'] = [
"trace_id" => $ddTraceSpan->getTraceId(),
"span_id" => $ddTraceSpan->getSpanId()
];
if (self::$isDebug) {
$record['context']['debug'] = self::$debugValue;
}
} catch (Exception $e) {
error_log($e->getMessage() . " Can't add trace to logs. Have you setup the Datadog Tracer extension? If you run a worker have your added the DD_TRACE_CLI_ENABLED env variable?");
}
return $record;
});
}
}