Skip to content
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

Configure the javaagent to log to a file (instead of stderr) #3413

Closed
mateuszrzeszutek opened this issue Jun 25, 2021 · 17 comments · Fixed by #7339
Closed

Configure the javaagent to log to a file (instead of stderr) #3413

mateuszrzeszutek opened this issue Jun 25, 2021 · 17 comments · Fixed by #7339
Labels
enhancement New feature or request

Comments

@mateuszrzeszutek
Copy link
Member

Is your feature request related to a problem? Please describe.
The aim of this issue is to add a new otel.javaagent.log-file (or something similar) property - when configured, the agent will use that file as the log output instead of logging everything to standard error.
Some users want to keep the agent logs separate from application logs; and with debug mode enabled I suppose that it can be more useful to have all the agent logs in a separate file, makes it easier to file a bug.

Additional context
You can already do that by setting io.opentelemetry.javaagent.slf4j.simpleLogger.logFile system property, but I guess that it'd be much nicer if we supported our own property (and env variable) and officially documented it.

@trask
Copy link
Member

trask commented Jul 1, 2021

logging to a file that doesn't roll over worries me

@anuraaga
Copy link
Contributor

anuraaga commented Jul 1, 2021

I think we've talked about logging before so I may just be forgetting a nuance. Is there any way we could make a best effort attempt to redirect our logs into the app's slf4j when it's available? Perhaps we can add a transformer to slf4j which statically registers it into some interface we provide in the bootstrap classloader. Having agent logs be configurable like the app would be so nice.

@trask
Copy link
Member

trask commented Jul 1, 2021

I think that starts to run into similar issues as using app's otel api/sdk. I think there's interest in solving those issues for otel api/sdk (#3261), which could lead to solution for slf4j too.

@mikeweisskopf
Copy link

I think a related issue comes with the use of logging libraries like logback in the actual application being instrumented. If you have logback configured to do application logging to a rotating set of files (using a RollingFileAppender) and run the application in a docker container then the javaagent logs will end up in the docker container logs (because the agent is logging to standard error) while all the rest of the application logs are in files managed by logback. We don't really want to have to manage logs separately (and remember where to look for what), but its not clear how to wire the two together as the agent starts up before the application (and its logback bootstrap).

@anuraaga
Copy link
Contributor

anuraaga commented Jul 8, 2021

I think that starts to run into similar issues as using app's otel api/sdk

The concept is definitely similar but I think logging should be much simpler though without needing a highly complex bridge given the API surface is much smaller (just ~4 methods, getLogger, warn, info, debug) and we would not be creating any types, just using stuff - one of the big complexities of otel api bridging is the need to create types in the agent for use in the app and vice versa, but nothing like that for logging. So basically just use reflection to access the app's slf4j version of those methods if no reflective exception or fallback to our shaded one that uses simplelogger. ClassLoader instrumentation can register a handle to the app's slf4j methods into the bootstrap classloader, somewhat like what we do for forceFlush. Or if we know how to add a static initializer with instrumentation, we could potentially avoid reflection with slf4j instrumentation that adds a static initializer to LoggerFactory which registers itself into the bootstrap classloader

@trask
Copy link
Member

trask commented Jul 8, 2021

ya, the part I think is tricky, is what to do in application server environments with multiple applications / copies of slf4j, though since this behavior would be opt-in, we can just document that restriction 👍

@mateuszrzeszutek
Copy link
Member Author

Or if we know how to add a static initializer with instrumentation, we could potentially avoid reflection with slf4j instrumentation that adds a static initializer to LoggerFactory which registers itself into the bootstrap classloader

Even if we did that, we could only register the "our slf4j" to "app slf4j" bridge after the agent has initialized and all instrumentations have been installed - everything that was logged earlier would still go to stderr.

@anuraaga
Copy link
Contributor

anuraaga commented Jul 8, 2021

everything that was logged earlier would still go to stderr.

Yep - in that sense, using reflection with classloader instrumentation does seem a bit better since it would reduce the number of messages that may end up missed. If we can get log messages printed during instrumentation of classes, and for LOGGING exporters into the app's slf4j that would be pretty good coverage.

@johnbley
Copy link
Member

Additionally / alternately, is there / should there be a way to completely suppress our usage of stderr (and just be silent, even about critical errors)?

@trask
Copy link
Member

trask commented Jul 13, 2021

Additionally / alternately, is there / should there be a way to completely suppress our usage of stderr (and just be silent, even about critical errors)?

For now at least, try -Dio.opentelemetry.javaagent.slf4j.simpleLogger.defaultLogLevel=off

@zmapleshine
Copy link
Contributor

zmapleshine commented Jul 14, 2021

Logs generated by the agent itself can sometimes be valuable, for example by printing out ’Timeout‘ or "Error" logs for a component and associating them with traceID to consume and clean them using something like Flink. The application itself doesn't care about these logs, so I think the agent's logs do need to be exported to a separate path.

@mateuszrzeszutek
Copy link
Member Author

Additionally / alternately, is there / should there be a way to completely suppress our usage of stderr (and just be silent, even about critical errors)?

Hmm, something like -Dotel.javaagent.no-logging=true? That would be a good thing to have too.

@jkwatson
Copy link
Contributor

logging to a file that doesn't roll over worries me

Whatever is built, it should have rolling logs built in as the default.

@trask
Copy link
Member

trask commented Jul 14, 2021

Hmm, something like -Dotel.javaagent.no-logging=true? That would be a good thing to have too.

Maybe -Dotel.javaagent.logging.level=debug/off/etc and -Dotel.javaagent.logging.file=... or similar?

@XiaoWeiKIN
Copy link

mark

@danhngo-lx
Copy link

For now at least, try -Dio.opentelemetry.javaagent.slf4j.simpleLogger.defaultLogLevel=off

Hi @trask, as I see we have switched to jul instead of slf4j, is this still valid? Or what is the right way to suppress the logs of the javaagent now?

@mateuszrzeszutek
Copy link
Member Author

Hi @danhngo-lx ,

Hi @trask, as I see we have switched to jul instead of slf4j, is this still valid? Or what is the right way to suppress the logs of the javaagent now?

Yes, it is still valid -- we're still using slf4j internally as the actual logging implementation (we're simply redirecting all those JUL calls).

mateuszrzeszutek pushed a commit that referenced this issue Apr 4, 2023
Related discussion #7257
Resolves #3413
Resolves #5059
Resolves #6258
Resolves #7179

Adds a logging implementation that'll collect agent logs in memory until
slf4j is detected in the instrumented application; and when that happens
will dump all the logs into the application slf4j and log directly to
the application logger from that time on.

It's still in a POC state, unfortunately: while it works fine with an
app that uses & initializes slf4j directly, Spring Boot applications
actually reconfigure the logging implementation (e.g. logback) a while
after slf4j is loaded; which causes all the startup agent logs (debug
included) to be dumped with the default logback pattern.

Future work:
* ~~Make sure all logs produces by the agent are sent to loggers named
`io.opentelemetry...`
(#7446
DONE
* Make this work on Spring Boot
* Documentation
* Smoke test?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
9 participants