Piotr,
Coming back to this after some months in the trenches.
On 6/4/25 3:37 PM, Piotr P. Karwasz wrote:
On 1.06.2025 17:36, Christopher Schultz wrote:
This is also very helpful. It sounds like I need a filter that simply
does not pass anything (i.e. filters everything). That would cause the
SmtpAppender to hold everything together. At the end (this is a
scheduled process which starts and ends, and I want to deliver at the
end of the process), how does one indicate to the appender that it's
time to "let it all go"? I don't necessarily want to log a message like
"done!" because I don't want that actually in the output. Will the
SmtpAppender automatically send on shutdown? I am currently calling
LogManager.shutdown() at the end of the process (log4j 1.x).
No, the `SmtpAppender` does not automatically send an email when it
stops. Calling `LogManager.shutdown()` does not trigger the appender to
flush or send buffered log events.
The `filter` element in the configuration is primarily intended for use
cases where you want an `ERROR` event to trigger an email that includes
some contextual lower-level log events from just before the error. Your
use case—delivering all log events at the end of a scheduled
process—seems quite different.
What you're describing is more aligned with batch logging, where logs
are buffered and sent in groups. Many database appenders[1] support this
behavior via a `bufferSize` attribute that controls how many events are
stored before being written.
Unfortunately, `SmtpAppender` does not support this kind of batching out
of the box, but it might be worth exploring whether we can add such a
feature.
[1] https://logging.apache.org/log4j/2.x/manual/appenders/database.html
I'll have a look at this, but my use case is this:
1. The cron-style program starts up and performs a few operations
2. Log messages bound for a client queue up
3. The process shuts-down, and the logs should be sent
I know when the process *will* shut-down, so I could send some kind of
custom message to the logger, etc. that says "okay go ahead and send".
I'm seriously considering no longer using "logging" for this operation
because it seems so tricky. I will have to change my APIs a little
because I'm using the lazy convenience of LogManager.getLogger()
returning a compatible instance of the logger from anywhere in the code,
rather than passing-around a "message accumulator" object, etc.
Because this is an email message to be sent to a client, I want to avoid
bombing them with many messages. So I need (a) suppression of triggering
an SMTP message for every log event and then (b) sending all queued log
events at a specific time.
I don't want to modify any files, here, if possible. The idea is to load
the "proper" configuration from the file as usual, but then be able to
enable or disable e.g. TRACE logging for specific loggers and/or
appenders as necessary.
Is there any way to do this kind of thing programmatically? I can see in
the Solr Dashboard that (a) log4j2 is being used and (b) appears to
allow the user to adjust the log level for all loggers through that
interface. I haven't gone into the code to figure out how it's done, but
it leads me to believe that everything can be done ephemerally in a
running JVM without writing any files or anything like that.
There is a Configurator[3] class in Log4j Core that lets you change log
levels programmatically. It's the recommended approach, but it comes
with two caveats:
- It only works with Log4j Core, not with other Log4j API
implementations. Replacing the logging backend would break this
functionality.
This might be okay, as I'm trying to provide this kind of setup as early
in the JVM process as possible. This is like enabling "verbose mode" on
a command-line program where you know you want to be in TRACE mode from
the first few lines of the program.
More specifically, I can try to avoid making *any* calls into the
logging system until I know that I want to be in TRACE mode.
My method in log4j 1.2 was to loop through every log4j.logger.* property
in the default properties loaded from the disk and change all their
values to TRACE *before* calling "new PropertyConfigurator()".
If there is a way to load the log4j config without actually initializing
everything, then modify that config, THEN initialize everything
downstream that would be ideal.
- It changes levels only for the logger context of the caller, which may
not be suitable in multi-user environments.
Back in November, I started working on a small API[4] that can list and
modify log levels independently of the logging implementation. I haven’t
made much progress since—I still need to address the question how to
prevent third-party libraries modifying the logging configuration
requested by the application developer (see Issue #1[5]).
I have another process that is very long-running where I'd like to do
the same thing, but I have much more control over the whole ecosystem of
loggers there, so I can ensure that only log4j2 is being used. Or, at
least, only log4j2 is being used in the code I where care about
modifying log levels.
I initially borrowed a pattern from Tomcat's JNDI implementation,
requiring a private token object to access the API. But that may be too
restrictive. Long term, I want this to support use cases like preventing
a Spring Boot app from adjusting global log levels in an application
container.
Would love your thoughts on how best to approach that.
-chris
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]