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 20 commits into
base: 5.x-dev
Choose a base branch
from
Open

Dev json logs #22994

wants to merge 20 commits into from

Conversation

krezreb
Copy link

@krezreb krezreb commented Jan 28, 2025

Description:

Modifies the LineMessageFormatter to support outputting of log messages as json (one json object per line). This has a number of benefits for observability:

  • No more multiline logs
  • Logs can now be parsed out of the box without having to write specific parsers
  • End-Users' ability to poison logs is limited as all logs are properly escaped

Also adds support for customers to add custom json processing to each line (useful for example for adding APM trace and span ids in for Datadog Unified service tagging users)

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 enable_json = true (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 matching 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

@krezreb krezreb requested review from michalkleiner and a team February 11, 2025 09:50
@patrickli
Copy link

@michalkleiner can you re-review this?

@michalkleiner michalkleiner self-assigned this Mar 10, 2025
michalkleiner
michalkleiner previously approved these changes Mar 13, 2025
Copy link
Contributor

@michalkleiner michalkleiner left a comment

Choose a reason for hiding this comment

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

Works as expected, tested the standard logging, the exclude parameters and the custom function mechanism.

@sgiehl can you think of any edge cases here?

@michalkleiner
Copy link
Contributor

I wonder whether it would be possible to keep the severity, date, tag and request ID alongside the message itself for easier filtering in the LogViewer.. at the moment it obviously all goes into the JSON string and then the filtering is not working.

Screenshot 2025-03-13 at 2 52 08 PM

@michalkleiner michalkleiner removed their assignment Mar 13, 2025
@michalkleiner michalkleiner added Enhancement For new feature suggestions that enhance Matomo's capabilities or add a new report, new API etc. c: Platform For Matomo platform changes that aren't impacting any of our APIs but improve the core itself. Needs Review PRs that need a code review labels Mar 13, 2025
@michalkleiner michalkleiner added this to the 5.4.0 milestone Mar 13, 2025
@patrickli
Copy link

No issues with the PR itself, but just don't name any field tag.

@krezreb
Copy link
Author

krezreb commented Mar 14, 2025

I wonder whether it would be possible to keep the severity, date, tag and request ID alongside the message itself for easier filtering in the LogViewer.. at the moment it obviously all goes into the JSON string and then the filtering is not working.

Screenshot 2025-03-13 at 2 52 08 PM

Um in my testing this screen worked with json logging enabled. Could you share your ini settings please?

@michalkleiner michalkleiner dismissed their stale review March 14, 2025 13:41

Tweak information in the LogViewer so that the fields are still filled with relevant information

@krezreb
Copy link
Author

krezreb commented Mar 14, 2025

I wonder whether it would be possible to keep the severity, date, tag and request ID alongside the message itself for easier filtering in the LogViewer.. at the moment it obviously all goes into the JSON string and then the filtering is not working.
Screenshot 2025-03-13 at 2 52 08 PM

Um in my testing this screen worked with json logging enabled. Could you share your ini settings please?

OK so identified the problem, there's dependent changes in the LogViewer sub repo, you also need to checkout the dev-json-logs branch

Copy link
Contributor

@michalkleiner michalkleiner left a comment

Choose a reason for hiding this comment

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

Requires a submodule update first, but otherwise this tested ok in the Log viewer area in Matomo as well as in the file output.

Copy link
Member

@sgiehl sgiehl left a comment

Choose a reason for hiding this comment

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

Introducing JSON logging sounds like a nice thing in general. But we maybe should do that in a more clean way and use more of the features we already have or monolog and/or DI allows us to.


'log.short.format' => Piwik\DI::factory(function (Container $c) {
if ($c->has('ini.log.enable_json')) {
Copy link
Member

Choose a reason for hiding this comment

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

This will actually also return true if enable_json = 0 is set in the config. Might be unexpected.

->constructorParameter('customFunctionFile', Piwik\DI::get('log.custom_function_file'))
->constructorParameter('excludePatterns', Piwik\DI::get('log.exclude_patterns')),

'log.custom_function_file' => Piwik\DI::factory(function (Container $c) {
Copy link
Member

Choose a reason for hiding this comment

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

Is there a specific reason why this is handled with a custom include file rather than using a LogProcessor class and configure using that LogProcessor by pre/appending it to log.processors di config?

{
$this->logMessageFormat = $logMessageFormat;
$this->allowInlineLineBreaks = $allowInlineLineBreaks;
$this->excludePatterns = $excludePatterns;
if ($customFunctionFile !== null) {
$this->customFunction = include_once $customFunctionFile;
Copy link
Member

Choose a reason for hiding this comment

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

Have you checked if that class is ALWAYS instantiated only once per request? If that happens a second time include_once will return true, instead of the files content.

}
}

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

Choose a reason for hiding this comment

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

I might have preferred having a dedicated JsonMessageFormatter class (maybe inheriting from this class) and decide which class to use within the DI config. That might be more clean than having one class for all that.

Comment on lines +235 to +237
->constructorParameter('allowInlineLineBreaks', false)
->constructorParameter('customFunctionFile', Piwik\DI::get('log.custom_function_file'))
->constructorParameter('excludePatterns', Piwik\DI::get('log.exclude_patterns')),
Copy link
Member

Choose a reason for hiding this comment

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

Only setting the constructor parameters here actually only allows using such new "features" for file logging. Any reason why that shouldn't be available for e.g. database or screen logging?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c: Platform For Matomo platform changes that aren't impacting any of our APIs but improve the core itself. Enhancement For new feature suggestions that enhance Matomo's capabilities or add a new report, new API etc. Needs Review PRs that need a code review
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants