Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev json logs #22994

Open
wants to merge 12 commits into
base: 5.x-dev
Choose a base branch
from
Open

Dev json logs #22994

wants to merge 12 commits into from

Conversation

krezreb
Copy link

@krezreb krezreb commented Jan 28, 2025

Description:

Please include a description of this change and which issue it fixes. If no issue exists yet please include context and what problem it solves.

Review

Depends on plugin PR matomo-org/plugin-LogViewer#99

To test json_logs

  1. Checkout the dev-json-logs branch on Matomo core
  2. Modify config/config.ini.php set the format as json in (see example below)
[log]
log_writers[] = file
log_level = DEBUG
enable_json = true
logger_file_path = tmp/logs/matomo.log
  1. Tail the the log file and you should see the logs as json
  2. Check the logviewer plugin index.php?module=LogViewer logs should appear correctly in the interface

To test exclude_pattens

  1. Modify config/config.ini.php set one or more exclude_patterns, separated by pipes(see example below)
[log]
log_writers[] = file
log_level = DEBUG
exclude_patterns =  "Piwik\Plugin\Manager|Matomo is not set up"
enable_json = true
logger_file_path = tmp/logs/matomo.log
  1. Tail the the log file and you should see the logs as json, EXCEPT FOR logs matching the exclude patterns

To test custom_function_file

  1. Modify config/config.ini.php specify custom_function_file (see example below)
[log]
log_writers[] = file
log_level = DEBUG
custom_function_file = /var/www/html/config/custom.php
enable_json = true
logger_file_path = tmp/logs/matomo.log
  1. Example custom.php
<?php

function userHandler(array $array) : ?array
{
        $array["foo"] = "bar";
        return $array;
};
# return a string mathcing the name of the above function
return 'userHandler';
  1. Tail the the log file and you should see the logs as json with the above custom logic run, in the above case a key "foo" will be set to the value "bar"

@patrickli
Copy link

{
$this->logMessageFormat = $logMessageFormat;
$this->allowInlineLineBreaks = $allowInlineLineBreaks;
$this->excludePatterns = $excludePatterns;
if (gettype($customFunctionFile) === "string") {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can add typehint to the constructor param and don't need to check for it being a string, just not empty.

private $allowInlineLineBreaks;

/**
* @param string $logMessageFormat
* @param bool $allowInlineLineBreaks If disabled, a log message will be created for each line
*/
public function __construct($logMessageFormat, $allowInlineLineBreaks = true)
public function __construct($logMessageFormat, $allowInlineLineBreaks = true, $excludePatterns = null, $customFunctionFile = null)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public function __construct($logMessageFormat, $allowInlineLineBreaks = true, $excludePatterns = null, $customFunctionFile = null)
public function __construct($logMessageFormat, $allowInlineLineBreaks = true, array $excludePatterns = null, string $customFunctionFile = null)

@@ -43,6 +48,21 @@ public function format(array $record)

$message = trim($record['message']);

if (gettype($this->excludePatterns) === "array") {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with the constructor mandated type of the param, this can just be

Suggested change
if (gettype($this->excludePatterns) === "array") {
if (!empty($this->excludePatterns)) {

}
}

if ($this->logMessageFormat == 'json') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might be a tad safer

Suggested change
if ($this->logMessageFormat == 'json') {
if ('json' === $this->logMessageFormat) {

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree about the === but is there a reason to put json first? legibility?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's the Yoda condition style, in general preventing situations when someone forgets an equal sign and accidentally assigns the value to the variable instead of doing a comparison. With the string or number first that can't happen. It's not a strict thing we check for in CS yet but might be at some point.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@michalkleiner hmm..... first time I've seen this, it is. Modify the line, I will

@@ -62,6 +82,27 @@ public function format(array $record)
return $total;
}

private function jsonMessage($class, $message, $date, $record)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we add typehints to the params and a return type?

"message" => $message,
"level" => $record['level_name'],
"trace" => $trace,
"requestId" => $requestId
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a trailing comma is preferred in case a new item is added to minimise git diff on unnecessary lines

Suggested change
"requestId" => $requestId
"requestId" => $requestId,

"requestId" => $requestId
];

if (gettype($this->customFunction) === "string") {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this might check for not being empty and also if it's actually callable

Suggested change
if (gettype($this->customFunction) === "string") {
if (is_callable($this->customFunction)) {

Comment on lines 242 to 246
$xcl = [];
foreach (explode("|", $c->get('ini.log.exclude_patterns')) as $p) {
$xcl[] = trim($p);
}
return $xcl;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
$xcl = [];
foreach (explode("|", $c->get('ini.log.exclude_patterns')) as $p) {
$xcl[] = trim($p);
}
return $xcl;
$excl = [];
foreach (explode('|', $c->get('ini.log.exclude_patterns')) as $p) {
$excl[] = trim($p);
}
return $excl;

$path = $c->get('ini.log.custom_function_file');
if (!file_exists($path)) {
return null;
throw new \Exception('Specified path to custom_function_file does not exist: ' . $path);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wont' be thrown if we return above it. Similar for the readability check.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@michalkleiner oh yeah that was test code I forgot to go back over. What do you think / what is our general philosophy in this case? Should the code fail silently or throw an exception and break logging?

Comment on lines 269 to 278
'log.exclude_patterns' => Piwik\DI::factory(function (Container $c) {
if ($c->has('ini.log.exclude_patterns')) {
$xcl = [];
foreach (explode("|", $c->get('ini.log.exclude_patterns')) as $p) {
$xcl[] = trim($p);
}
return $xcl;
}
return null;
}),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems like a duplicated section

Suggested change
'log.exclude_patterns' => Piwik\DI::factory(function (Container $c) {
if ($c->has('ini.log.exclude_patterns')) {
$xcl = [];
foreach (explode("|", $c->get('ini.log.exclude_patterns')) as $p) {
$xcl[] = trim($p);
}
return $xcl;
}
return null;
}),

Comment on lines +281 to +283
if ($c->has('ini.log.enable_json')) {
return 'json';
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we not pass this just via ini.log.string_message_format below?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@michalkleiner I considered that but I found adding a new option is probably easier for users to understand. Also, in the viewer code https://github.com/matomo-org/plugin-LogViewer/blob/5a7687b3591566aa5cdd1235241e06fa9891415b/Log/Parser/Piwik.php#L25 doesn't use the format so might be a dead feature anyway

Comment on lines +291 to +293
if ($c->has('ini.log.enable_json')) {
return 'json';
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we not pass it via ini.log.string_message_format_trace below?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above, looks like a dead feature

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants