Logging Module

Last modified by Thomas Mortagne on 2024/07/05 18:09

cogAllows to easily manipulate logging
TypeJAR
Category
Developed by

XWiki Development Team

Rating
0 Votes
LicenseGNU Lesser General Public License 2.1
Bundled With

XWiki Standard

Description

This module allows any component to manipulate logs in the following way:

  • receive logs as events
  • isolate log in for a specific task without it to appear in the standard log

The user interface documentation can be found on Logging Application.

This documentation is not about logging from Java Components. For that see the Component Module.

Features

Deprecation warnings

Various module log warning when deprecated API or features are used. In production you often want to disable those warning because you use some extensions which have to support old version of XWiki or because you want to focus on more important issue which might become hard to see.

You can enable/disable those warning using the property logging.deprecated.enabled in the file xwiki.properties.

Modules willing produce such warnings should org.xwiki.logging.LoggerConfiguration#isDeprecatedLogEnabled() API to check if they should log them or not.

Logs as events

To receive log a component can listen to org.xwiki.logging.event.LogEvent events. See Observation Module for more details on how to listen to events.

import org.xwiki.logging.LogLevel;
import org.xwiki.logging.event.AbstractLogEventListener;
import org.xwiki.observation.event.Event;

@Component
@Named("MyLogListener")
@Singleton
public class MyLogListener extends AbstractLogEventListener
{
   @Override
   public String getName()
   {
       return "MyLogListener";
   }

   @Override
   public void onEvent(Event event, Object source, Object data)
   {
        LogEvent logEvent = (LogEvent) event;

       if (logEvent.getLevel() == LogLevel.ERROR) {
            System.err.println(logEvent.getFormattedMessage());
       } else if (logEvent.getLevel() == LogLevel.WARN) {
            System.err.println(logEvent.getFormattedMessage());
       } else if (logEvent.getLevel() == LogLevel.INFO) {
            System.out.println(logEvent.getFormattedMessage());
       } else if (logEvent.getLevel() == LogLevel.DEBUG) {
            System.out.println(logEvent.getFormattedMessage());
       } else if (logEvent.getLevel() == LogLevel.TRACE) {
            System.out.println(logEvent.getFormattedMessage());
       }
   }
}

Log isolation

Sometime for a specific task you want to report detailed log to the user of the UI but don't want to pollute the system log. For this you can use org.xwiki.logging.LoggerManager default component.

It provide way to push and pop overwriting log receiver as event listener.

Here is an example:

LogQueue queue = new LogQueue();

loggerManager.pushLogListener(new LogListener("loglistenerid", queue));
logger.error("Some application error happen");
loggerManager.popLogListener();

Since 11.9 it's possible to force a log to end up in the system log even when it's grabbed by passing the org.xwiki.logging.Logger#ROOT_MARKER marker.

logger.error(org.xwiki.logging.Logger.ROOT_MARKER, "Critical problem for the whole platform");

Manipulate loggers log level

It's possible to get or modify all registered loggers.

Get all registered loggers

  Collection<Logger> loggers = loggerManager.getLoggers();

Set log level

The following example set the level DEBUG to org.xwiki package and all sub-packages (unless one of the sub-packages override it).

  loggerManager.setLoggerLevel("org.xwiki", LogLevel.DEBUG)

Get log level

The following example return the log level of the package org.xwiki.

  loggerManager.getLoggerLevel("org.xwiki")

Translate log

It's possible to provide a translation key when logging, using SLF4J's Marker support. That allows logging listeners (classes extending org.xwiki.logging.event.AbstractLogEventListener for example) receiving logging events (org.xwiki.logging.event.LogEvent) to be able to get that information and use a localization framework to convert the translation key to the translated version.

Log producer example:

  logger.error(new TranslationMarker("someapplication.error"), "Some application error happen");

Log displayer example:

  #set($translatedLogEvent = $services.logging.translate($logEvent))
  $translatedLogEvent.formattedMessage

Parameterized and translatable exceptions

XWiki 14.10.1+, 15.0+ A org.xwiki.logging.AbstractMessageException is provided to make easier to create exceptions based on org.xwiki.logging.Message. They expose a similar API than logger to create them, so it's possible to pass translation key and parameters to benefit from logging module translation tools when displaying those extensions messages in the UI.

Log tree

It's possible to organize a set of logs as a tree using org.xwiki.logging.event.LogEvent#MARKER_BEGIN and org.xwiki.logging.event.LogEvent#MARKER_END markers.

  logger.info(LogEvent.MARKER_BEGIN, "Start some task");
  logger.error("Failed to do part of the task");
  logger.info(LogEvent.MARKER_END, "Task is done but failed");

  logger.info(LogEvent.MARKER_BEGIN, "Start a different task");
  logger.info(LogEvent.MARKER_END, "Task has ended well");

You can use org.xwiki.logging.LogTree to properly interpret such a log and get helpers to navigate into the tree.

The logging ScriptService also provide a helper to convert a log list into a tree:

#set($logtree = $services.logging.toLogTree($logs))

Supported implementations

To provide theses feature this module actually need to have specific support for each logging system because there is no way at the SLF4J level to catch logs and setup actual loggers. Right now only Logback is supported but should not be too hard to add support for other systems like Log4j for example.

Logger tail

since 11.9

It's possible to create a org.xwiki.logging.tail.LoggerTail using org.xwiki.logging.LoggerManager component. Contrary to LogQueue it's stored on filesystem for several reasons:

  • very low memory footprint
  • live log

It provides both APIs to append log and navigate in it.

Scripting

A org.xwiki.script.service.ScriptService is provided with the name logging.

Get a Logger from script

[since 6.1]

You can ask for a proper SLF4J Logger using  #getLogger(String name). Here is an example in velocity:

$services.logging.getLogger('My script').info('Hello {}', 'world')

Note that you'll need to enable the logger in the Logback configuration. If you wish to test quickly, you could use the org.xwiki logger which is already enabled for the info level. For example:

$services.logging.getLogger('org.xwiki').info('Hello {}', 'world')

Log a deprecation warning

XWiki 13.1+

It's possible to log automatically a deprecation warning in a script, to inform users that some scripts might be removed in the future. This method checks the deprecation warnings configuration to only display the message if it is enabled.
You can use it like this:

## First argument is the logger name, second is the message.
$services.logging.deprecate("MyScript", "The script [MyScript] should not be used anymore")

The output warning is displayed with a [DEPRECATED]  prefix.

Get Connected