| 1 |
<?php declare(strict_types=1); |
| 2 |
/** |
| 3 |
* Stackdriver via Fluentd formatter for Monolog |
| 4 |
* |
| 5 |
* Handles all features of Stackdriver via Fluentd formatter for Monolog. |
| 6 |
* |
| 7 |
* @package Formatters |
| 8 |
* @author Pierre Lannoy <https://pierre.lannoy.fr/>. |
| 9 |
* @since 1.0.0 |
| 10 |
*/ |
| 11 |
|
| 12 |
namespace Decalog\Formatter; |
| 13 |
|
| 14 |
use Decalog\System\Http; |
| 15 |
use DLMonolog\Formatter\FormatterInterface; |
| 16 |
use Decalog\Plugin\Feature\EventTypes; |
| 17 |
|
| 18 |
/** |
| 19 |
* Define the Monolog Stackdriver via Fluentd formatter. |
| 20 |
* |
| 21 |
* Handles all features of Stackdriver via Fluentd formatter for Monolog. |
| 22 |
* |
| 23 |
* @package Formatters |
| 24 |
* @author Pierre Lannoy <https://pierre.lannoy.fr/>. |
| 25 |
* @since 1.0.0 |
| 26 |
*/ |
| 27 |
class StackdriverFormatter implements FormatterInterface { |
| 28 |
|
| 29 |
/** |
| 30 |
* Formats a log record. |
| 31 |
* |
| 32 |
* @param array $record A record to format. |
| 33 |
* @return string The formatted record. |
| 34 |
* @since 1.0.0 |
| 35 |
*/ |
| 36 |
public function format( array $record ): string { |
| 37 |
if ( array_key_exists( $record['level'], EventTypes::$level_names ) ) { |
| 38 |
$level = EventTypes::$level_names[ $record['level'] ]; |
| 39 |
} else { |
| 40 |
$level = 'DEFAULT'; |
| 41 |
} |
| 42 |
$tag = strtolower( DECALOG_PRODUCT_SHORTNAME . '.' . $record['channel'] . '.' . $level ); |
| 43 |
$message = [ |
| 44 |
'severity' => $level, |
| 45 |
'message' => $record['message'], |
| 46 |
'context' => $record['context'], |
| 47 |
'extra' => $record['extra'], |
| 48 |
]; |
| 49 |
if ( array_key_exists( 'file', $record['extra'] ) && $record['extra']['file'] && is_string( $record['extra']['file'] ) ) { |
| 50 |
$message['logging.googleapis.com/sourceLocation']['file'] = $record['extra']['file']; |
| 51 |
} |
| 52 |
if ( array_key_exists( 'line', $record['extra'] ) && $record['extra']['line'] ) { |
| 53 |
$message['logging.googleapis.com/sourceLocation']['line'] = (int) $record['extra']['line']; |
| 54 |
} |
| 55 |
if ( array_key_exists( 'function', $record['extra'] ) && $record['extra']['function'] && is_string( $record['extra']['function'] ) ) { |
| 56 |
$message['logging.googleapis.com/sourceLocation']['function'] = $record['extra']['function']; |
| 57 |
if ( array_key_exists( 'class', $record['extra'] ) && $record['extra']['class'] && is_string( $record['extra']['class'] ) ) { |
| 58 |
$message['logging.googleapis.com/sourceLocation']['function'] = $record['extra']['class'] . '::' . $message['logging.googleapis.com/sourceLocation']['function']; |
| 59 |
} |
| 60 |
} |
| 61 |
if ( array_key_exists( 'ip', $record['extra'] ) && is_string( $record['extra']['ip'] ) ) { |
| 62 |
$message['httpRequest']['remoteIp'] = $record['extra']['ip']; |
| 63 |
} |
| 64 |
if ( array_key_exists( 'url', $record['extra'] ) && is_string( $record['extra']['url'] ) ) { |
| 65 |
$message['httpRequest']['requestUrl'] = $record['extra']['url']; |
| 66 |
} |
| 67 |
if ( array_key_exists( 'http_method', $record['extra'] ) && is_string( $record['extra']['http_method'] ) ) { |
| 68 |
if ( in_array( strtolower( $record['extra']['http_method'] ), Http::$verbs, true ) ) { |
| 69 |
$message['httpRequest']['requestMethod'] = strtoupper( $record['extra']['http_method'] ); |
| 70 |
} |
| 71 |
} |
| 72 |
if ( array_key_exists( 'code', $record['context'] ) && is_numeric( $record['context']['code'] ) ) { |
| 73 |
if ( 0 < (int) $record['context']['code'] && array_key_exists( (int) $record['context']['code'], Http::$http_status_codes ) ) { |
| 74 |
$message['httpRequest']['status'] = (int) $record['context']['code']; |
| 75 |
} |
| 76 |
} |
| 77 |
if ( array_key_exists( 'referrer', $record['extra'] ) && is_string( $record['extra']['referrer'] ) ) { |
| 78 |
$message['httpRequest']['referer'] = $record['extra']['referrer']; |
| 79 |
} |
| 80 |
if ( array_key_exists( 'ua', $record['extra'] ) && is_string( $record['extra']['ua'] ) ) { |
| 81 |
$message['httpRequest']['userAgent'] = $record['extra']['ua']; |
| 82 |
} |
| 83 |
$message['logging.googleapis.com/labels']['decalog.wordpress.org/logger'] = 'StackdriverHandler'; |
| 84 |
$message['logging.googleapis.com/labels']['decalog.wordpress.org/version'] = DECALOG_VERSION; |
| 85 |
$message['logging.googleapis.com/labels']['decalog.wordpress.org/context/class'] = $record['context']['class']; |
| 86 |
$message['logging.googleapis.com/labels']['decalog.wordpress.org/context/component'] = $record['context']['component']; |
| 87 |
$message['logging.googleapis.com/labels']['decalog.wordpress.org/context/channel'] = $record['channel']; |
| 88 |
return wp_json_encode( [ $tag, $record['datetime']->getTimestamp(), $message ] ); |
| 89 |
} |
| 90 |
/** |
| 91 |
* Formats a set of log records. |
| 92 |
* |
| 93 |
* @param array $records A set of records to format. |
| 94 |
* @return string The formatted set of records. |
| 95 |
* @since 1.0.0 |
| 96 |
*/ |
| 97 |
public function formatBatch( array $records ): string { |
| 98 |
$message = ''; |
| 99 |
foreach ( $records as $record ) { |
| 100 |
$message .= $this->format( $record ); |
| 101 |
} |
| 102 |
return $message; |
| 103 |
} |
| 104 |
} |
| 105 |
|