• No results found

Lookup Variables with Multiple Leading '$' Characters

5 Configuration

5.1 Configuration

5.1.7 Lookup Variables with Multiple Leading '$' Characters

An interesting feature of StrLookup processing is that when a variable reference is declared with multiple leading '$' characters each time the variable is resolved the leading '$' is simply removed. In the previous example the "Routes" element is capable of resolving the variable at runtime. To allow this the prefix value is specified as a variable with two leading '$' characters. When the configuration file is first processed the first variable is simply removed. Thus, when the Routes element is evaluated at runtime it is the variable declaration "${sd:type}" which causes the event to be inspected for a StructuredDataMessage and if one is present the value of its type attribute to be used as the routing

key. Not all elements support resolving variables at runtime. Components that do will specifically call that out in their documentation.

If no value is found for the key in the Lookup associated with the prefix then the value associated with the key in the properties declaration in the configuration file will be used. If no value is found the variable declaration will be returned as the value. Default values may be declared in the configuration by doing: <?xml version="1.0" encoding="UTF-8"?> <Configuration> <Properties> <Property name="type">Audit</property> </Properties> ... </Configuration>

As a footnote, it is worth pointing out that the variables in the RollingFile appender declaration will also not be evaluated when the configuration is processed. This is simply because the resolution of the whole RollingFile element is deferred until a match occurs. See RoutingAppender for more information.

5.1.8 Scripts

Log4j provides support for JSR 223 scripting languages to be used in some of its components. Any language that provides support for the JSR 223 scripting engine may be used. A list of the languages and bindings for them can be found at the Scripting Engine web site. However, some of the languages listed there, such as JavaScript, Groovy and Beanshell, directly support the JSR 223 scripting framework and only require that the jars for that language be installed.

The components that support using scripts do so by allowing a <script>, <scriptFile>, or <scriptRef> element to be configured on them. The script element contains a name for the script, the language of the script, and the script text. The scriptFile element contains the name of the script, its location, its language, its charset, and whether the file should be watched for changes. The scriptRef element contains the name of the script that is defined in the <scripts> configuration element. The name of the script is used to store the script, along with its ScriptEngine, so it can quickly be located each time the script needs to be run. While the name is not required, providing it will help in debugging problems when the script is running. The language must be provided on the script element and must specify one of the language names that appear in the Configuration status log as described in the next section. If the language is not specified on the scriptFile element the language will be determined by the file extension of the script path. If file monitoring is requested it will only be enabled if a non- zero monitorInterval is specified on the configuration element. That interval will be used to check for changes in the file.

<?xml version="1.0" encoding="UTF-8"?>

<Configuration status="debug" name="RoutingTest"> <Scripts>

<Script name="selector" language="javascript"><![CDATA[ var result;

if (logEvent.getLoggerName().equals("JavascriptNoLocation")) { result = "NoLocation";

} else if (logEvent.getMarker() != null && logEvent.getMarker().isInstanceOf("FLOW")) { result = "Flow";

} result; ]]></Script>

<ScriptFile name="groovy.filter" path="scripts/filter.groovy"/> </Scripts>

<Appenders>

<Console name="STDOUT">

<ScriptPatternSelector defaultPattern="%d %p %m%n"> <ScriptRef ref="selector"/>

<PatternMatch key="NoLocation" pattern="[%-5level] %c{1.} %msg%n"/>

<PatternMatch key="Flow" pattern="[%-5level] %c{1.} ====== %C{1.}.%M:%L %msg ======%n"/> </ScriptPatternSelector>

<PatternLayout pattern="%m%n"/> </Console>

</Appenders>

<Loggers>

<Logger name="EventLogger" level="info" additivity="false"> <ScriptFilter onMatch="ACCEPT" onMisMatch="DENY">

<Script name="GroovyFilter" language="groovy"><![CDATA[

if (logEvent.getMarker() != null && logEvent.getMarker().isInstanceOf("FLOW")) { return true; } else if (logEvent.getContextMap().containsKey("UserId")) { return true; } return false; ]]> </Script> </ScriptFilter> <AppenderRef ref="STDOUT"/> </Logger> <Root level="error">

<ScriptFilter onMatch="ACCEPT" onMisMatch="DENY"> <ScriptRef ref="groovy.filter"/> </ScriptFilter> <AppenderRef ref="STDOUT"/> </Root> </Loggers> </Configuration>

If the status attribute on the Configuration element is set to DEBUG the list of script engines currently installed and their attributes will be listed. Although some engines may say they are not thread safe, Log4j takes steps to insure that the scripts will run in a thread-safe manner if the engine advertises that it is not thread safe.

2015-09-27 16:13:22,925 main DEBUG Installed script engines

2015-09-27 16:13:22,963 main DEBUG AppleScriptEngine Version: 1.1, Language: AppleScript, Threading: Not Thread Safe, Compile: false, Names: {AppleScriptEngine, AppleScript, OSA}

2015-09-27 16:13:22,983 main DEBUG Groovy Scripting Engine Version: 2.0, Language: Groovy, Threading: MULTITHREADED, Compile: true, Names: {groovy, Groovy}

2015-09-27 16:13:23,030 main DEBUG BeanShell Engine Version: 1.0, Language: BeanShell, Threading: MULTITHREADED, Compile: true, Names: {beanshell, bsh, java}

2015-09-27 16:13:23,039 main DEBUG Mozilla Rhino Version: 1.7 release 3 PRERELEASE, Language: ECMAScript, Threading: MULTITHREADED, Compile: true, Names: {js, rhino, JavaScript, javascript, ECMAScript, ecmascript}

When the scripts are executed they will be provided with a set of variables that should allow them to accomplish whatever task they are expected to perform. See the documentation for the individual components for the list of variables that are available to the script.

The components that support scripting expect a return value to be passed back to the calling Java code. This is not a problem for several of the scripting languages, but Javascript does not allow a return statement unless it is within a function. However, Javascript will return the value of the last statement executed in the script. As a consequence, code such as that shown below will result in the desired behavior.

var result;

if (logEvent.getLoggerName().equals("JavascriptNoLocation")) { result = "NoLocation";

} else if (logEvent.getMarker() != null && logEvent.getMarker().isInstanceOf("FLOW")) { result = "Flow";

} result;

5.1.8.1 A special note on Beanshell

JSR 223 scripting engines are supposed to identify that they support the Compilable interface if they support compiling their scripts. Beanshell does this. However, whenever the compile method is called it throws an Error (not an Exception). Log4j catches this but will log the warning shown below for each Beanshell script when it tries to compile them. All Beanshell scripts will then be interpreted on each execution.

2015-09-27 16:13:23,095 main DEBUG Script BeanShellSelector is compilable

2015-09-27 16:13:23,096 main WARN Error compiling script java.lang.Error: unimplemented at bsh.engine.BshScriptEngine.compile(BshScriptEngine.java:175)

at bsh.engine.BshScriptEngine.compile(BshScriptEngine.java:154)

at org.apache.logging.log4j.core.script.ScriptManager$MainScriptRunner.<init>(ScriptManager.java:125) at org.apache.logging.log4j.core.script.ScriptManager.addScript(ScriptManager.java:94)

5.1.9 XInclude

XML configuration files can include other files with XInclude. Here is an example log4j2.xml file that includes two other files:

<?xml version="1.0" encoding="UTF-8"?> <configuration xmlns:xi="http://www.w3.org/2001/XInclude" status="warn" name="XIncludeDemo"> <properties> <property name="filename">xinclude-demo.log</property> </properties> <ThresholdFilter level="debug"/> <xi:include href="log4j-xinclude-appenders.xml" /> <xi:include href="log4j-xinclude-loggers.xml" /> </configuration> log4j-xinclude-appenders.xml: <?xml version="1.0" encoding="UTF-8"?> <appenders> <Console name="STDOUT"> <PatternLayout pattern="%m%n" /> </Console>

<File name="File" fileName="${filename}" bufferedIO="true" immediateFlush="true"> <PatternLayout> <pattern>%d %p %C{1.} [%t] %m%n</pattern> </PatternLayout> </File> </appenders> log4j-xinclude-loggers.xml: <?xml version="1.0" encoding="UTF-8"?> <loggers>

<logger name="org.apache.logging.log4j.test1" level="debug" additivity="false"> <ThreadContextMapFilter>

<KeyValuePair key="test" value="123" /> </ThreadContextMapFilter>

<AppenderRef ref="STDOUT" /> </logger>

<logger name="org.apache.logging.log4j.test2" level="debug" additivity="false"> <AppenderRef ref="File" /> </logger> <root level="error"> <AppenderRef ref="STDOUT" /> </root> </loggers>

Related documents