Instrumentation feature#471
Conversation
|
|
||
| ClassLoader currentThreadClassLoader = Thread.currentThread().getContextClassLoader(); | ||
| URLClassLoader urlClassLoader = new URLClassLoader(urls.toArray(new URL[]{}), currentThreadClassLoader); | ||
| Thread.currentThread().setContextClassLoader(urlClassLoader); |
There was a problem hiding this comment.
Do not rely on Thread.contextClassLoader please.
If you want to offer a flag allowing custom listener code to be loaded, do not do it this way. First of all, stop using system properties; introduce a real option with documentation. Then have it somehow specify the location of a JAR and/or class name(s) to load from it in a fresh class loader.
(Nicest would be to use SezPoz but adding a new library dep for this purpose is likely overkill, and anyway it would potentially clash with the copy loaded from jenkins-core.jar.)
There was a problem hiding this comment.
For example, define a hook as a JAR whose manifest has a Main-Class entry giving the FQN of a class implementing whichever listener interface makes sense, with a public no-arg constructor. Then define a CLI arg
-listener /path/to/impl.jarWhen specified, the hook would be loaded in its own private URLClassLoader parented to that of agent.jar.
| } catch (ClassNotFoundException e) { | ||
| LOGGER.log(Level.WARNING, String.format("Failed to load %s", listenerName), e); | ||
| success = false; | ||
| } catch (NoSuchMethodException e) { | ||
| LOGGER.log(Level.WARNING, String.format("Failed to get constructor of %s", listenerName), e); | ||
| success = false; | ||
| } catch (InvocationTargetException | InstantiationException | IllegalAccessException e) { | ||
| LOGGER.log(Level.WARNING, String.format("Failed to instantiate %s", listenerName), e); |
There was a problem hiding this comment.
KISS
| } catch (ClassNotFoundException e) { | |
| LOGGER.log(Level.WARNING, String.format("Failed to load %s", listenerName), e); | |
| success = false; | |
| } catch (NoSuchMethodException e) { | |
| LOGGER.log(Level.WARNING, String.format("Failed to get constructor of %s", listenerName), e); | |
| success = false; | |
| } catch (InvocationTargetException | InstantiationException | IllegalAccessException e) { | |
| LOGGER.log(Level.WARNING, String.format("Failed to instantiate %s", listenerName), e); | |
| } catch (Exception e) { | |
| LOGGER.log(Level.WARNING, "Failed to load " + listenerName, e); | |
| success = false; |
| if (listener instanceof EngineInstrumentationListener) { | ||
| instrumentation.add((EngineInstrumentationListener) listener); | ||
| LOGGER.log(Level.INFO, String.format("Loaded an external engine instrumentation listener (%s)", listenerName)); | ||
| } else { | ||
| LOGGER.log(Level.WARNING, String.format("Failed to use %s. Not an instance of %s", listenerName, EngineInstrumentationListener.class.getCanonicalName())); | ||
| success = false; | ||
| } |
There was a problem hiding this comment.
Java’s built-in CCEs in newer versions are better than any message you come up with.
| if (listener instanceof EngineInstrumentationListener) { | |
| instrumentation.add((EngineInstrumentationListener) listener); | |
| LOGGER.log(Level.INFO, String.format("Loaded an external engine instrumentation listener (%s)", listenerName)); | |
| } else { | |
| LOGGER.log(Level.WARNING, String.format("Failed to use %s. Not an instance of %s", listenerName, EngineInstrumentationListener.class.getCanonicalName())); | |
| success = false; | |
| } | |
| instrumentation.add((EngineInstrumentationListener) listener); | |
| LOGGER.log(Level.INFO, "Loaded an external engine instrumentation listener ({0})", listenerName); |
|
I would actually suggest considering a different design altogether. Use the existing remoting/src/main/java/hudson/remoting/EngineListener.java Lines 41 to 67 in dd0a1a6 remoting/src/main/java/hudson/remoting/Channel.java Lines 643 to 692 in dd0a1a6 default methods as needed for finer-grained or more informative events) and otherwise do nothing in remoting. Rather, make a Jenkins plugin which injects listener code into the agent when it connects. There are various examples of this already. This would make it much easier to distribute various listener implementations (just use the update center); there is no need to adjust the startup arguments for agent.jar; the Remoting code stays cleaner. The only downside is that you would not get access to details of what is going on before the connection is established.
|
I see this survey but it is not obvious to me that the extra bit of diagnostics possible with the current approach is worth making the distribution and configuration of the listener much more awkward. Typically the problem is sporadic disconnection; if you cannot connect at all, there are better ways to diagnose that directly, not using general telemetry. Not sure what “robust against agent restart” is about. With the plugin approach, if the agent restarts, Jenkins will see a new |
|
Thank you so much for your review and advice! I'll provide a short answer for
before going to bed.
I agree with this and I thought the plugin approach would work well but I found that, in the UNIX agent, UnixSlaveRestarter restarts the agent with code: https://github.com/jenkinsci/jenkins/blob/95e85495ca6b26ba61ff4a1bf18d181d5e218bc9/core/src/main/java/jenkins/slaves/restarter/UnixSlaveRestarter.java#L50-L63 So if we take the plugin approach, the monitoring program will be killed every time sporadic disconnection happens. And we cannot collect the trace of the next connection and metrics after the sporadic disconnection. I think this information can be useful for troubleshooting and that's what I mean by "not robust against agent restart". |
|
Generally, I agree with Jesse's comments and recommendations, particularly about keeping it simple. Launching the agent is already complicated enough -- it's important not to further complicate that. If the feature is valuable we need to implement reasonable support for it. While I understand users would like to have diagnostics about what happens before a connection is completed, I doubt they would actually find anything useful there. I wouldn't prioritize that as a high-value feature or sacrifice other improvements for that. |
|
Thank you so much for a lot of feedback! |
|
I'll close this PR, thank you so much for your feedback! context: jenkinsci/remoting-opentelemetry-plugin#65 (comment) |
|
Sorry for not following up on the discussion
…On Tue, Jul 27, 2021 at 10:26 AM Akihrio Kiuchi ***@***.***> wrote:
Closed #471 <#471>.
—
You are receiving this because your review was requested.
Reply to this email directly, view it on GitHub
<#471 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAW4RIEXAWBYDRWAIUG5DYTTZZUTZANCNFSM5ALR5J3Q>
.
|
Proposal to introduce remoting instrumentation feature.
Related to GSoC '21 Remoting Monitoring project.
In the Remoting Monitoring project, we are trying to observe the behavior of remoting modules using OpenTelemetry. And users will be able to visualize the remoting behavior like this.
To collect more accurate and valuable data, we want to introduce a new feature to observe the remoting module.
What I did
-cpflag for Java9+-cpflag in Java9+, but somehow valuable.LauncherInstrumentationListenerandEngineInstrumentationListeneronRunWithStdinStdoutLauncherInstrumentationListenerandEngineInstrumentationListener-cpflagLauncherInstrumentationListenerAdapterorEngineInstrumentationListenerAdapterCommand example
Some references regarding the
-cpflag.#468
#443
https://issues.jenkins.io/browse/JENKINS-64831
I would appreciate any negative or positive feedback!