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
Feature/log appender per pipeline #11108
Conversation
Jenkins test this please |
e4dd715
to
2a9ed3c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've done some initial testing on this, and confirmed that log entries are added to separate per-pipeline log files if enabled.
Most of my remarks are around tidying up the config, along with a question over duplication of log entries across per-pipeline logs and the main logstash log, and whether that should be required, optional or not done..
config/log4j2.properties
Outdated
appender.routing.routes.route_pipelines.rolling.layout.type = PatternLayout | ||
appender.routing.routes.route_pipelines.rolling.layout.pattern = %d %p %C{1.} [%t] %m%n | ||
appender.routing.routes.route_pipelines.rolling.policy.type = SizeBasedTriggeringPolicy | ||
appender.routing.routes.route_pipelines.rolling.policy.size = 500 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs to be increased before commiting
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, I'll bring the same configs used for the main log
config/log4j2.properties
Outdated
appender.routing.routes.script.type = Script | ||
appender.routing.routes.script.name = routing_script | ||
appender.routing.routes.script.language = JavaScript | ||
appender.routing.routes.script.value = logEvent.getContextData().containsKey("pipeline.id") ? logEvent.getContextMap().get("pipeline.id") : "sink"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason why getContextData
and (deprecated) getContextMap
are both in use here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getContextMap
was a cut/paste not changed to getContextData
import java.util.Properties; | ||
|
||
@Plugin(name = "LogstashConfigurationFactory", category = ConfigurationFactory.CATEGORY) | ||
@Order(9) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the significance of 9?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the order that Log4J2 uses to load the plugins. The standard log4 PropertiesConfigurationFactory
has Order = 8, higher means more priority
config/log4j2.properties
Outdated
appender.routing.routes.route_pipelines.rolling.fileName = ${sys:ls.logs}/pipeline_${ctx:pipeline.id}.log | ||
appender.routing.routes.route_pipelines.rolling.filePattern = ${sys:ls.logs}/pipeline_${ctx:pipeline.id}.%i.log.gz | ||
appender.routing.routes.route_pipelines.rolling.layout.type = PatternLayout | ||
appender.routing.routes.route_pipelines.rolling.layout.pattern = %d %p %C{1.} [%t] %m%n |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably try and keep the formatting consistent with that used in other log entries, something like:
[%d{ISO8601}][%-5p][%-25c] %m%n
(although I'm not necessarily averse to introducing the thread to the log)
appender.routing.routes.route_pipelines.rolling.filePattern = ${sys:ls.logs}/pipeline_${ctx:pipeline.id}.%i.log.gz | ||
appender.routing.routes.route_pipelines.rolling.layout.type = PatternLayout | ||
appender.routing.routes.route_pipelines.rolling.layout.pattern = %d %p %C{1.} [%t] %m%n | ||
appender.routing.routes.route_pipelines.rolling.policy.type = SizeBasedTriggeringPolicy |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we also need to setup a rollover strategy here?
@@ -44,6 +44,7 @@ module Environment | |||
Setting::Boolean.new("pipeline.java_execution", true), | |||
Setting::Boolean.new("pipeline.reloadable", true), | |||
Setting::Boolean.new("pipeline.plugin_classloaders", false), | |||
Setting::Boolean.new("pipeline.separate_logs", false), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I notice from testing, that we get log entries produced in the pipeline duplicated in the pipeline logs, and in the main log. This leads me to wonder:
How do we want to handle this:
a) Duplicate all per-pipeline log entries in the per-pipeline logs and the main log
b) Separate all per-pipeline log entries into the per-pipeline logs only.
c) Allow the user to choose main, per-pipeline or both for pipeline log entries.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that if the log goes in the pipeline logs it shouldn't be present also in the main
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
++ to b), if you set separate_logs
, then pipeline-specific log entries should not land in the main log file
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed by commit 1ad14ee
System.setProperty("ls.logs", "build/logs"); | ||
System.setProperty(LogstashConfigurationFactory.PIPELINE_SEPARATE_LOGS, "true"); | ||
|
||
ThreadContext.clearAll(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to put this into a @after/tearDown
to avoid the ThreadContext potentially polluting other tests?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, something like that to avoid the test having any unforeseen side effects - we might even be able to use @BeforeClass
and @AfterClass
to set and unset the properties, and an @Rule
to handle the ThreadContext -
@Rule
public ThreadContextRule threadContextRule = new ThreadContextRule();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I do it, I didn't used the @Rule
because in JUnit5 does not exists rules as I read, so be open moving to JUnit5 without incur in deprecated stuff.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah! I missed that @Rule
was a junit5 thing. No worries!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed by 3ab931e
Jenkins test this please |
@robbavey this is ready to be reviewed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@andsel Couple of concerns - firstly running this on JDK 11 the following error message is emitted:
Warning: Nashorn engine is planned to be removed from a future JDK release
It is emitted every time a pipeline log entry is written if pipeline.separate_logs
is set to true
, less frequently if it is set to false
Presumably this is due to the use of javascript in the log4j2.properties
file.
Secondly, when pipelines.separate_logs
is set to true
, log entries that are re-directed to separate log files no longer appear in the console logs. I think by default, we would still want to have those entries emitted via the console, and only separated in the log files. What do you think @jsvd?
appender.routing.routes.route1.type = Route | ||
appender.routing.routes.route1.list.type = List | ||
appender.routing.routes.route1.list.name = appender-${mdc:pipeline.id} | ||
#appender.routing.routes.route1.rolling.type = RollingFile |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove commented out code before commit
@@ -38,10 +38,63 @@ | |||
} | |||
IO.write(@ls.application_settings_file, settings.to_yaml) | |||
@ls.spawn_logstash("-w", "1" , "-e", config) | |||
@ls.wait_for_logstash | |||
sleep 2 until @ls.exited? | |||
#@ls.wait_for_logstash |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove commented out code before commit
} | ||
IO.write(@ls.application_settings_file, settings.to_yaml) | ||
@ls.spawn_logstash("-w", "1" , "-e", config) | ||
#@ls.wait_for_logstash |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove commented out code before commit
@robbavey @jsvd to make the console appender continue printing the log lines also in case the Regarding the Nashorn warning we could disable with a |
@andsel Personally, I think it makes sense to remove the filtering part from the console. And I think removing the Nashorn deprecation warning is ok for now. It may even be possible to use By the way, do you know if there is any sort of performance impact on introducing scripting into the logging routing? |
@robbavey I've checked with JMH benchmark, and if the benchmark is correct, the output says that we loose not so much:
|
Jenkins test this please |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couple of questions on the benchmarks. Everything else is good, I think
@@ -45,6 +45,10 @@ dependencies { | |||
compile 'commons-io:commons-io:2.5' | |||
runtime 'joda-time:joda-time:2.8.2' | |||
compile "org.jruby:jruby-core:$jrubyVersion" | |||
// compile 'org.apache.logging.log4j:log4j-api:2.11.1' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did these need to be commented out?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was a try to fix a console log in benchmark.
Launch the benchmark with ./gradlew jmh -Pinclude="org.logstash.benchmark.LogPerPipelineBenchmark.*"
On the console I've many lines like this:
ERROR StatusLogger Unrecognized conversion specifier [d] starting at position 16 in conversion pattern.
ERROR StatusLogger Unrecognized format specifier [thread]
ERROR StatusLogger Unrecognized conversion specifier [thread] starting at position 25 in conversion pattern.
ERROR StatusLogger Unrecognized format specifier [level]
ERROR StatusLogger Unrecognized conversion specifier [level] starting at position 35 in conversion pattern.
ERROR StatusLogger Unrecognized format specifier [logger]
ERROR StatusLogger Unrecognized conversion specifier [logger] starting at position 47 in conversion pattern.
ERROR StatusLogger Unrecognized format specifier [msg]
ERROR StatusLogger Unrecognized conversion specifier [msg] starting at position 54 in conversion pattern.
ERROR StatusLogger Unrecognized format specifier [n]
ERROR StatusLogger Unrecognized conversion specifier [n] starting at position 56 in conversion pattern.
2019-09-13 10:49:14,358 org.logstash.benchmark.LogPerPipelineBenchmark.logWithScriptingCodeToExecute-jmh-worker-1 ERROR Unable to locate plugin type for Loggers
2019-09-13 10:49:14,363 org.logstash.benchmark.LogPerPipelineBenchmark.logWithScriptingCodeToExecute-jmh-worker-1 ERROR Unable to locate plugin type for Appenders
And I don't know why
|
||
@Benchmark | ||
@OperationsPerInvocation(EVENTS_PER_INVOCATION) | ||
public final void logWithoutScriptingCodeToExecute() throws Exception { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: These two tests are basically the same test with only the System property changing, so redundant code can be removed.
#appender.console.avoid_pipelined_filter.script.type = Script | ||
#appender.console.avoid_pipelined_filter.script.name = filter_no_pipelined | ||
#appender.console.avoid_pipelined_filter.script.language = JavaScript | ||
#appender.console.avoid_pipelined_filter.script.value = ${sys:ls.pipeline.separate_logs} == false || !(logEvent.getContextData().containsKey("pipeline.id")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does uncommenting this block to enable the filter have any effect on the performance?
I think there might be 3 tests - no scripting in log4j
files, scripting with separate_logs = false
and scripting with separate_logs = true
.
574dba9
to
67ba711
Compare
67ba711
to
356cef2
Compare
0d41698
to
cce5431
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One issue with the nashorn args in jvm.options
config/jvm.options
Outdated
@@ -79,3 +79,6 @@ | |||
|
|||
# Copy the logging context from parent threads to children | |||
-Dlog4j2.isThreadContextMapInheritable=true | |||
|
|||
# Avoid Nashorn deprecation logs in JDK > 11 | |||
-Dnashorn.args="--no-deprecation-warning" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Testing this locally did not work with the quotes in place, but did without
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed, I was testing with flag passed directly in my IDE
cce5431
to
c02fcb1
Compare
c02fcb1
to
cce5431
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@andsel One more thing! Can we add a commented out section to logstash.yml
explaining the new setting?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Can you please merge this into master
and 7.x
…logs per pipelines - use log4j RoutingAppender - avoid output to main log files when log per pipeline is enabled - closes 10427
ae8fdf9
to
3028c37
Compare
…logs per pipelines - use log4j RoutingAppender - avoid output to main log files when log per pipeline is enabled - closes 10427 Fixes #11108
This PR is related to issue #10427 and introduce the separation of pipeline logs in separate appenders.
It leverage the log4j2 RoutingAppender (https://logging.apache.org/log4j/2.x/manual/appenders.html#RoutingAppender), by default it's switched off and could be enabled with the config flag
--pipeline.separate_logs=true/false
. To disable this feature it's used a custom PropertiesConfigFactory that simply remove the routing appender at startup phase if it's switched off. It expecte to find a routing appender namedpipeline_routing_appender