Thanks a lot for the tips guys! tl;dr - skip to the end for my final, simple solution.
I'm a bit hesitant to adding expression filters to do this filtering. The root of the issue is that I want to set the package log level using the regular, standard way (so that anyone can do it/understand it from the properties file), but I want my loggers to output a bit of extra info whenever they print a line, so I know what instance is doing what.
The MDC/NDC stuff looks very interesting, but I'm looking for per logger granularity, not per thread. When a thread traverses an object graph and does work in each object, I want the object to tell me which instance it is when it prints it's log lines, regardless if the worker is Thread-4 or Thread-34 etc.
I had found that this is sort of a tall order as the architecture doesn't really do this sort of thing (according to my primitive knowledge of it), but I made it pretty close (with some blocking caveats) with a custom logger.
I ended up finding out about custom loggers and log factories from the <Install Zip>/examples/subclass folder. I threw together a new logger ('DescriptiveLogger') and a factory for it. The DescriptiveLogger has a description field and overrides all the default logging to prepend the message with this description.
The system works out fine until I want to create two loggers with the same name/package with a different description. When I try DescriptiveLogger.getLogger(existingClassAkaPackage, newDescription), it will change the original/old logger and update it with the new description, but I want a whole new instance.
This is due to the Hierarchy implementation - it stores all the loggers in a hashtable that is keyed by the logger name (which is the same for all my loggers, but I'd like a separate instance for each one so they can each have their own description).
So after pouring over the source, I've finally found the trivial ideal solution. Beforehand I was using getLogger("ImportantDevice: This instance has ID 23"), which would give me the information I wanted in the log, but wouldn't allow me to easily user per-package log levels through the properties file. The alternative log creation, namely getLogger(ImportantDevice.class) would give me the log level control I wanted, but wouldn't give me the instance information I crave.
The solution is to use getLogger(ImportantDevice.class.getName()+": This instance has ID 23"). Now the logger name is prefixed with the package, which allows log4j to apply package log level rules to it, and the logger name is also suffixed with the extra information I was looking for. It took more time then I was hoping to figure this out (and I didn't get to employ anything cool), but I expect that at least one other person on here may be able to find it useful.
Regards, Charles On 7/18/2012 10:55 AM, Scott Deboy wrote:
Correction: expression would use the LOGGER instead of MSG, since you're filtering on that. On Wed, Jul 18, 2012 at 10:54 AM, Scott Deboy<[email protected]> wrote:You can use filters, including the ExpressionFilter, to build pretty much arbitrary expressions and filter appenders using that, but it requires you to use a log4j.xml configuration file. Something like this (requires you to have the 'extras' companion in your classpath): <filter class="org.apache.log4j.filter.ExpressionFilter"> <param name="Expression" value="MSG ~= #3"/> <param name="AcceptOnMatch" value="false"/> </filter> Scott On Wed, Jul 18, 2012 at 10:26 AM, Charles Hache<[email protected]> wrote:Hello folks, Most of my loggers are constructed with the Logger.getLogger(String) function, so that I can have loggers like "Device(#3, Some Description)" instead of "ca.something.package.Device" with the goal of being able to more easily identify which instances are writing what log lines. I've found that when I do this I can't use properties to filter the log level, such as log4j.logger.ca.something.**package=INFO I figure this is because if I use getLogger(Device.class) it gets the package of the logger from the class I give it and it all works from there. So this all makes sense, but brings up two questions: Can I still declare my loggers with a String name (getLogger(String)) and somehow still use package-style log level selection in the properties file? If not, do you guys have any tips on how to differentiate between instances when they're logging? The obvious solution would be to prepend any log message I want to write with a description of the instance, but that seems like a lot of extra work. I think really what I'm looking for is something like getLogger(Class theClass, String theName), but maybe there is an already-implemented way to do this. Any tips? Regards, Charles ------------------------------**------------------------------**--------- To unsubscribe, e-mail:log4j-user-unsubscribe@**logging.apache.org<[email protected]> For additional commands, e-mail:log4j-user-help@logging.**apache.org<[email protected]>
-- Charles Hache Manager, Software Systems Technical Solutions Company Ltd. 101 Titanium Way, Unit 105 Whitehorse, Yukon Y1A 0E7 Tel 867-668-6588, Ext. 204 Cell 867-336-1484 Fax 866-528-6410 [email protected] Webwww.tsco.ca Technical Solutions Company Ltd. Automation - Telemetry - Electronics - Communications --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
