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
Better service name and version detection #1327
Comments
@felixbarny Could you give me a few pointers to deal with that? |
I gave a bit of thought after reading #1725 (comment) I think we can make it more generic than just doing it specifically for the Servlet API. What we could do on the first invocation of That would probably work generically for any framework by looking up the service name based on the manifest entry when the first transaction of any given service starts. It can also help to determine the service name early enough in the startup process for the automatic ECS log reconfiguration (#1261) to add the correct It needs validation but it seems worth trying it out. |
I played with it a little bit here: https://github.com/tobiasstadler/apm-agent-java/tree/poc-service-name-and-version. It lacks tests and documentation, but It my it (mostly) works for me. |
This looks great! It has one issue, though. It assumes that the agent is attached at startup via -javaagent. However, we also support runtime attachment. At the point in time when the agent is runtime-attached, all the initializers might have already run. Is there a particular reason why you preferred resolving the service name and version so early in the startup process, as opposed to resolving them when the first transaction is started? The latter seems easier, wouldn't require technology-specific instrumentations, and works with runtime attachment. But maybe I'm missing something why it's important to resolve the service name/version early. |
Another thing to consider is that a single JVM may have multiple service names, for example when multiple web applications (e.g. |
I implemented early service name/version detection because in case of Application Servers transactions might already be created before the first request hits the application. E.g. during deployment using startup EJBs or CDI events or after deployment using scheduled EJBs. Also the are applications which might not have a http interface because they only process JMD/Kafka/... messages. In this cases the transactions will have the „wrong“ service name/version, if more than one application is deployed on the same application server. |
The service name set via |
Yes my approach won‘t work with runtime attachment. But as I only use the javaagent and I have intention to change that, I haven‘t put much effort in supporting runtime attachment yet. |
That would also be handled with my suggestion: on the first transaction, no matter if it's a servlet request or a CDI event, the service name would be determined using the initiating class loader that's a required parameter when creating a transaction. That works with both runtime and startup attachment and doesn't require implementing technology-specific startup instrumentations. |
I am fine with that. But one still has to implement service name/version detection for the none servlet case. |
But no matter if servlet or not, the service name detection would work the same way, by looking up the |
There might be more than one META-INF/MANIFEST.MF on the class/module path. How would you like to determine which one is the "correct" one? |
As the order of resources is more or less class loader dependent, I think it is quite hard to finde the application META-INF/MANIFEST.MF |
Isn't that already an issue for the advices you implemented that depend on class loader lookup of
Or are you saying that while it's fine to do that for the servlet API, it doesn't work for the general case? |
I think it is safe to use The specification also states: "The getResource and getResourceAsStream methods take a String with a leading “/” as an argument that gives the path of the resource relative to the root of the context or relative to the META-INF/resources directory of a JAR file inside the web application’s WEB-INF/lib directory". So in my opinion ServletContext.getResource("META-INF/MANIFEST") should not return a manifest file from a dependency. But I am not really sure if I read hat correctly. On the other side |
@felixbarny I find you approach very interesting, better und more maintainable then what I did. I just don't know how to find the right manifest file. |
That's a very valid point and I haven't considered it. I'm also not sure how we could reliably find the right manifest file. Maybe we can get the resources as URLs and check whether they're inside |
Some observations using Spring Boot 2.0 and embedded Tomcat:
Not sure if that's something we can generalize, such as always the second one or always the one before the agent's manifest file. |
@felixbarny How should we proceed? I would like to get #1726 or sth. similar committed, so I can use the undertow plugin of my poc (as an external plugin) |
Thanks to @tobiasstadler we made good progress on this. I've updated the issue description to track the different tasks. Seems the attempt to generically get the manifest based just on the class loader is not fruitful. But as we can now get the manifest of standalone jars, we just need to focus on getting the manifest for different web applications. The
Can we just instrument
That's not an issue because we can now get the manifest from the standalone jar directly, without relying on the |
I think we can close this now as done. We have excellent service name and version detection now. We might look into instrumenting container-specific hooks in the future to be able to detect the service name earlier. But that would just be an additional improvement on top. See also #2443 (comment) |
Currently, the only way to take advantage of the deployment tracking is to use the
service_version
configuration option.We could get the version from the
MANIFEST.MF
Implementation-Version
entries.While doing that, we might also want to read the
Implementation-Title
entry, if available to determine theservice.name
.Spring Boot seems to set both of these entries.
Tasks
ServletContextListener#contextInitialized
#2443The text was updated successfully, but these errors were encountered: