Scripts
Log4j provides support for JSR 223 scripting languages to be used in some of its components.
In order to enable a scripting language, its name must be included in the
|
Each component that allows scripts can contain on of the following configuration elements:
- Script
-
This element specifies the content of the script directly and has:
-
a required
language
configuration attribute that specifies the name of the JSR 223 language to use, -
a required
scriptText
configuration attribute that contains the text of the script. In the XML configuration format, the text of the script can also be written as content of the<Script>
XML element. This allows the usage of aCDATA
block.
The element can be assigned a name using the
name
configuration attribute.See also Plugin reference.
-
- ScriptFile
-
This element points to an external script file and has:
-
a required
path
attribute that points to the path to a file name. -
an optional
language
attribute that specifies the name of the JSR 223 language to use. If not provided, the language is deduced from the extension of the file. -
an optional
isWatched
attribute. If set totrue
the script file will be monitored for changes.
The element can be assigned a name using the
name
configuration attribute.See also Plugin reference.
-
- ScriptRef
-
This element references a named script from the global Scripts container plugin in the configuration file.
See also Plugin reference.
The environment in which the script runs is different for each Log4j script-based component.
-
XML
-
JSON
-
YAML
-
Properties
log4j2.xml
<Appenders>
<Console name="STDOUT">
<PatternLayout>
<ScriptPatternSelector defaultPattern="%d %p %m%n">
<ScriptRef ref="SELECTOR_SCRIPT"/>
<PatternMatch key="NoLocation" pattern="[%-5level] %c{1.} %msg%n"/>
<PatternMatch key="Flow"
pattern="[%-5level] %c{1.} ====== %C{1.}.%M:%L %msg ======%n"/>
</ScriptPatternSelector>
</PatternLayout>
</Console>
</Appenders>
<Loggers>
<Logger name="EventLogger">
<ScriptFilter onMatch="ACCEPT" onMismatch="DENY">
<Script name="EVENT_LOGGER_FILTER" 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>
</Logger>
<Root level="INFO">
<ScriptFilter onMatch="ACCEPT" onMismatch="DENY">
<ScriptRef ref="ROOT_FILTER"/>
</ScriptFilter>
<AppenderRef ref="STDOUT"/>
</Root>
</Loggers>
<Scripts>
<Script name="SELECTOR_SCRIPT" 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="ROOT_FILTER" path="scripts/filter.groovy"/>
</Scripts>
log4j2.json
"Appenders": {
"Console": {
"name": "STDOUT",
"PatternLayout": {
"ScriptPatternSelector": {
"defaultPattern": "%d %p %m%n",
"ScriptRef": {
"ref": "SELECTOR_SCRIPT",
"PatternMatch": [
{
"key": "NoLocation",
"pattern": "[%-5level] %c{1.} %msg%n"
},
{
"key": "Flow",
"pattern": "[%-5level] %c{1.} ====== %C{1.}.%M:%L %msg ======%n"
}
]
}
}
}
}
},
"Loggers": {
"Logger": {
"name": "EventLogger",
"ScriptFilter": {
"onMatch": "ACCEPT",
"onMismatch": "DENY",
"Script": {
"name": "EVENT_LOGGER_FILTER",
"language": "groovy",
"scriptText": "if (logEvent.getMarker() != null && logEvent.getMarker().isInstanceOf('FLOW'))) { return true; } else if (logEvent.getContextMap().containsKey('UserId')) { return true; } return false;"
}
}
},
"Root": {
"level": "INFO",
"ScriptFilter": {
"onMatch": "ACCEPT",
"onMismatch": "DENY",
"ScriptRef": {
"ref": "ROOT_FILTER"
}
},
"AppenderRef": {
"ref": "STDOUT"
}
}
},
"Scripts": {
"Script": {
"name": "SELECTOR_SCRIPT",
"language": "javascript",
"scriptText": "var result; if (logEvent.getLoggerName().equals('JavascriptNoLocation')) { result = 'NoLocation'; } else if (logEvent.getMarker() != null && logEvent.getMarker().isInstanceOf('FLOW')) { result = 'Flow'; } result;"
},
"ScriptFile": {
"name": "ROOT_FILTER",
"path": "scripts/filter.groovy"
}
}
log4j2.yaml
Appenders:
Console:
name: "STDOUT"
PatternLayout:
ScriptPatternSelector:
defaultPattern: "%d %p %m%n"
ScriptRef:
ref: "SELECTOR_SCRIPT"
PatternMatch:
- key: "NoLocation"
pattern: "[%-5level] %c{1.} %msg%n"
- key: "Flow"
pattern: "[%-5level] %c{1.} ====== %C{1.}.%M:%L %msg ======%n"
Loggers:
Logger:
name: "EventLogger"
ScriptFilter:
onMatch: "ACCEPT"
onMismatch: "DENY"
Script:
name: "EVENT_LOGGER_FILTER"
language: "groovy"
scriptText: |
if (logEvent.getMarker() != null
&& logEvent.getMarker().isInstanceOf("FLOW")) {
return true;
} else if (logEvent.getContextMap().containsKey("UserId")) {
return true;
}
return false;
Root:
level: "INFO"
ScriptFilter:
onMatch: "ACCEPT"
onMismatch: "DENY"
ScriptRef:
ref: "ROOT_FILTER"
AppenderRef:
ref: "STDOUT"
Scripts:
Script:
name: "SELECTOR_SCRIPT"
language: "javascript"
scriptText: |
var result;
if (logEvent.getLoggerName().equals("JavascriptNoLocation")) {
result = "NoLocation";
} else if (logEvent.getMarker() != null
&& logEvent.getMarker().isInstanceOf("FLOW")) {
result = "Flow";
}
result;
ScriptFile:
name: "ROOT_FILTER"
path: "scripts/filter.groovy"
log4j2.properties
appender.0.type = Console
appender.0.name = STDOUT
appender.0.layout.type = PatternLayout
appender.0.layout.selector = ScriptPatternSelector
appender.0.layout.selector.defaultPattern = %d %p %m%n
appender.0.layout.selector.scriptRef.type = ScriptRef
appender.0.layout.selector.scriptRef.ref = SELECTOR_SCRIPT
appender.0.layout.selector.match[0].type = PatternMatch
appender.0.layout.selector.match[0].key = NoLocation
appender.0.layout.selector.match[0].pattern = [%-5level] %c{1.} %msg%n
appender.0.layout.selector.match[1].type = PatternMatch
appender.0.layout.selector.match[1].key = Flow
appender.0.layout.selector.match[1].pattern = \
[%-5level] %c{1.} ====== %C{1.}.%M:%L %msg ======%n
logger.0.name = EventLogger
logger.0.filter.0.type = ScriptFilter
logger.0.filter.0.onMatch = ACCEPT
logger.0.filter.0.onMismatch = DENY
logger.0.filter.0.script.type = Script
logger.0.filter.0.script.name = EVENT_LOGGER_FILTER
logger.0.filter.0.script.language = groovy
logger.0.filter.0.script.scriptText = \
if (logEvent.getMarker() != null\
&& logEvent.getMarker().isInstanceOf("FLOW"))) {\
return true;\
} else if (logEvent.getContextMap().containsKey("UserId")) {\
return true;\
}\
return false;
rootLogger.level = INFO
rootLogger.filter.0.type = ScriptFilter
rootLogger.filter.0.onMatch = ACCEPT
rootLogger.filter.0.onMismatch = DENY
rootLogger.filter.0.scriptRef.type = ScriptRef
rootLogger.filter.0.scriptRef.ref = ROOT_FILTER
rootLogger.appenderRef.0.ref = STDOUT
script.0.type = Script
script.0.name = SELECTOR_SCRIPT
script.0.language = javascript
script.0.scriptText = \
var result;\
if (logEvent.getLoggerName().equals("JavascriptNoLocation")) {\
result = "NoLocation";\
} else if (logEvent.getMarker() != null\
&& logEvent.getMarker().isInstanceOf("FLOW")) {\
result = "Flow";\
}\
result;
script.1.type = ScriptFile
script.1.name = ROOT_FILTER
script.1.path = scripts/filter.groovy
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 extend the Compilable
interface, but an attempt to compile a script ends up in an
Error
being thrown.
Log4j catches the throwable, but issues a warning in Status Logger.
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)