P6log

Platform 6 logging Consumer receives and filters log4j events.

log4j is the logging framework used by platform6. Other logging frameworks such as jdk, slf4j and commons are also redirected to log4j as are stdout and stderr streams. This means that nearly everything logged or written to an output stream by core p6 code, third-party libraries or Groovy scripts is captured.

For more information about log4j 1.2 see this: http://logging.apache.org/log4j/1.2/manual.html

A custom log4j appender called ‘platform6’ is defined in the log4j.properties file:

log4j.appender.platform6 = com.amalto.b2box.core.impl.logging.B2boxAppender

This appender will generate events via the p6log component and allows low level filtering by logger Level and Logger Name

Common Usage Scenarios

Email Errors to an Operator

All ERROR level logs are captured, stored and sent as xml to an route endpoint where they are filtered and used to generate an Active Routing Order by the p6route component.

The routing order is typically configured to transform the xml to an html document that is sent as an email body to an operator via the SMTP service

Send log messages to an ELK server

All ERROR and WARN logs are captured in JSON format and posted as strings to the ELASTICSEARCH audit provider

Configuration Attributes

Event Queue

There is an internal queue used to store log events awaiting processing. The size of this queue can be controlled by the following conf attribute:

  • com.amalto.b2box.core.impl.application.camel.p6log.LogConsumer.QueueSize default: “2048”

Limiter

It is very easy to introduce recursion to your p6log routes especially if the scripts called as a result of an event generate ERRORs! To protect against an out of control recursion a limiter is used. By default, this ensures no more than ten matching log events can be processed within any five second period (additional events will be discarded).

The following conf attributes can be modified to change this default behaviour:

  • com.amalto.b2box.core.impl.application.camel.p6log.LogConsumer.limiter.capacity default:”10”
  • com.amalto.b2box.core.impl.application.camel.p6log.LogConsumer.limiter.resetValue default:”10”
  • com.amalto.b2box.core.impl.application.camel.p6log.LogConsumer.limiter.resetMillis default:”5000”

URI Format

p6log://[?options]

Options

The P6log component supports three options which are described below.

Name Description Default Type
level log4j logger Level >= ERROR string
nameRegex Match required on ‘Logger Name’ string
format Log formatting, either: json, xml or map xml string
persistXml true to store xml in LOG partition false string

Example of an xml formatted log event

This format is historical in design and mirrors the logging events generated by the B2BOX product.

<logging_event>
    <id>93a64239b5d811e8a1120c4de9a356bc</id>
    <time>2018-09-11 17:37:22.950 CEST</time>
    <level>ERROR</level>
    <logger>GROOVYSCRIPT: Simons_MacBook_Pro_local_ScriptModule__GENERATE_ERROR</logger>
    <message>this is an error!</message>
    <ndc></ndc>
    <thread>P6JobRunner_Pool-Thread-3</thread>
</logging_event>

Example

Template: BaseRoute.groovy

${addRoutes} :=

from("p6log://?level=ERROR&format=json")
    .description('JSON ERROR Log Listener')
    .to( "p6cmb://scripts?platform6.request.action=execute&id=ErrorLogger" )
    .routeId('JSONlLogListener')

Template: BaseRoute.groovy

${addRoutes} :=

from('p6log://?persistXml=true')
    .description('Xml ERROR Log Listener')
    .to("direct:p6router.1")
    .routeId('ClassicXmlLog_Listener')

from('direct:p6router.1')
.description('Xml ERROR Log Routing Rule')
.choice()
    .when(xpath("/logging_event/level='ERROR'"))
        .setHeader( 'platform6.request.action').constant('execute')
        .setHeader('id').constant('XMLErrorTest')
        .setProperty('execute.async').constant(true)
        .to( 'p6route://scripts')

.otherwise()
    .throwException(com.amalto.b2box.core.api.B2boxException,'No matching rule found for item!')

.end()
.routeId('ClassicXmlLog_Router')

Script ErrorLogger:

def jsonLogError = p6.pipeline.get('body')
p6.audit.post('myerrorindex', jsonLogError)

Script XmlErrorTest:

def htmlToEmail = p6.xslt.process( "LoggingEvent", resource.get('LoggingEvent'), p6.transaction.getUsingPipelineRequest() )

if( p6.email.sendHtmlEmail( 'dev.platform6.io@amalto.com', 
                            'simon.temple@amalto.com', 
                            htmlToEmail, 
                            ['subject': '[DEV P6] localhost - Logging Event'], null ) ){

    // Remove the stored logging_event after you processed it
    def item = p6.transaction.remove( p6.transaction.getPKUsingPipelineRequest() )
    assert item != null 
}