-
Notifications
You must be signed in to change notification settings - Fork 322
Adding InitializationTelemetry - e.g. guard rails reporting #7287
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
Changes from all commits
e37b454
e31388e
a6e86c6
65d71d7
1ea0d0d
0f65b9f
122bf2b
7cc2251
b60ad48
22e5542
d75864f
b4623d6
2453d4d
60c7981
ca42c53
405ca3c
34e3781
c0245ae
6b5676a
9cc6da6
b5ae75a
19cfbbd
ef25275
a084432
a16fe75
7694c6c
f4c19de
623004a
79cf2ea
d44e73c
3812431
97b429f
60406b4
f44d294
de0b7eb
fe2a16a
319b87b
a9ffb10
bf26a18
2754fa2
b6a80db
d729531
79197c1
deb8831
13e5272
536b940
5784379
93c5107
73dca78
e95d976
c0b3f77
d1d886b
7137af6
91a892e
aa76a5c
416f728
83b0eaa
08ffeb7
982282f
651b125
01dccb0
22f9192
e1e17fc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,213 @@ | ||||||
| package datadog.trace.bootstrap; | ||||||
|
|
||||||
| import java.lang.invoke.MethodHandle; | ||||||
| import java.lang.invoke.MethodHandles; | ||||||
| import java.lang.invoke.MethodType; | ||||||
|
|
||||||
| /** | ||||||
| * Thread safe wrapper around BootstrapInitializationTelemetry used inside the Datadog ClassLoader. | ||||||
| * | ||||||
| * <p>Right now, this is needed because of the build separation between the two portions of the | ||||||
| * bootstrap. We should consider adjusting the build to allow Agent et al to reference | ||||||
| * BootstrapInitializationTelemetry, then we could remove this proxy. | ||||||
| */ | ||||||
| public abstract class InitializationTelemetry { | ||||||
| /** Returns a proxy around a BoostrapInitializationTelemetry object */ | ||||||
| public static final InitializationTelemetry proxy(Object bootstrapInitTelemetry) { | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd prefer to keep final almost everywhere, but I decided to remove the final where it is redundant because the class is final. In this case, the class isn't final. So I'm keeping the final because I don't want someone to override this method on a child class. |
||||||
| if (bootstrapInitTelemetry == null) { | ||||||
| return InitializationTelemetry.noOpInstance(); | ||||||
| } else { | ||||||
| return new BootstrapProxy(bootstrapInitTelemetry); | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| /** Returns a singleton of the no op InitializationTelemetry */ | ||||||
| public static final InitializationTelemetry noOpInstance() { | ||||||
| return NoOp.INSTANCE; | ||||||
| } | ||||||
|
|
||||||
| /** | ||||||
| * Indicates that an abort condition occurred during the bootstrapping process. Abort conditions | ||||||
| * are assumed to leave the bootstrapping process incomplete. {@link #markIncomplete()} | ||||||
| */ | ||||||
| public abstract void onAbort(String reasonCode); | ||||||
|
|
||||||
| /** | ||||||
| * Indicates that an exception occurred during the bootstrapping process By default the exception | ||||||
| * is assumed to NOT have fully stopped the initialization of the tracer. | ||||||
| * | ||||||
| * <p>If this exception stops the core bootstrapping of the tracer, then {@link #markIncomplete()} | ||||||
| * should also be called. | ||||||
| */ | ||||||
| public abstract void onError(Throwable t); | ||||||
|
|
||||||
| /** | ||||||
| * Indicates an exception that occurred during the bootstrapping process that left initialization | ||||||
| * incomplete. Equivalent to calling {@link #onError(Throwable)} and {@link #markIncomplete()} | ||||||
| */ | ||||||
| public abstract void onFatalError(Throwable t); | ||||||
|
|
||||||
| /** | ||||||
| * Indicates that an exception conditional occurred during the bootstrapping process. By default | ||||||
| * the exceptional condition is assumed to NOT have fully stopped the initialization of the | ||||||
| * tracer. | ||||||
| * | ||||||
| * <p>If this exception stops the core bootstrapping of the tracer, then {@link #markIncomplete()} | ||||||
| * should also be called. | ||||||
| */ | ||||||
| public abstract void onError(String reasonCode); | ||||||
|
|
||||||
| /** | ||||||
| * Marks bootstrapping of tracer as an incomplete Should only be called when a core (e.g. | ||||||
| * non-optional) component fails to initialize | ||||||
| */ | ||||||
| public abstract void markIncomplete(); | ||||||
|
|
||||||
| /** No telemetry - used for delayed initialization outside bootstrap invocation */ | ||||||
| static final class NoOp extends InitializationTelemetry { | ||||||
| static final NoOp INSTANCE = new NoOp(); | ||||||
|
|
||||||
| NoOp() {} | ||||||
|
|
||||||
| @Override | ||||||
| public void onAbort(String reasonCode) {} | ||||||
|
|
||||||
| @Override | ||||||
| public void onError(String reasonCode) {} | ||||||
|
|
||||||
| @Override | ||||||
| public void onError(Throwable t) {} | ||||||
|
|
||||||
| @Override | ||||||
| public void onFatalError(Throwable t) {} | ||||||
|
|
||||||
| @Override | ||||||
| public void markIncomplete() {} | ||||||
| } | ||||||
|
|
||||||
| /** Reflective proxy to BootstrapInitializationTelemetry */ | ||||||
| static final class BootstrapProxy extends InitializationTelemetry { | ||||||
| private final Object bootstrapInitTelemetry; | ||||||
| private volatile MethodHandle bmh_onAbortString; | ||||||
| private volatile MethodHandle bmh_onErrorString; | ||||||
| private volatile MethodHandle bmh_onErrorThrowable; | ||||||
| private volatile MethodHandle bmh_onFatalErrorThrowable; | ||||||
| private volatile MethodHandle bmh_markIncomplete; | ||||||
|
|
||||||
| // DQH - Decided not to eager access MethodHandles, since exceptions are uncommon | ||||||
| // However, MethodHandles are cached on lookup | ||||||
|
|
||||||
| /** @param bootstrapInitTelemetry - non-null BootstrapInitializationTelemetry */ | ||||||
| BootstrapProxy(final Object bootstrapInitTelemetry) { | ||||||
| this.bootstrapInitTelemetry = bootstrapInitTelemetry; | ||||||
| } | ||||||
|
|
||||||
| @Override | ||||||
| public void onAbort(String reasonCode) { | ||||||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd like to figure out a better way to test this proxy. |
||||||
| MethodHandle bmh_onAbortString = this.bmh_onAbortString; | ||||||
| if (bmh_onAbortString == null) { | ||||||
| bmh_onAbortString = findBoundHandle("onAbort", String.class); | ||||||
| this.bmh_onAbortString = bmh_onAbortString; | ||||||
| } | ||||||
| if (bmh_onAbortString != null) { | ||||||
| try { | ||||||
| bmh_onAbortString.invokeExact(reasonCode); | ||||||
| } catch (Throwable t) { | ||||||
| // ignore | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| @Override | ||||||
| public void onError(String reasonCode) { | ||||||
| MethodHandle bmh_onErrorString = this.bmh_onErrorString; | ||||||
| if (bmh_onErrorString == null) { | ||||||
| bmh_onErrorString = findBoundHandle("onError", String.class); | ||||||
| this.bmh_onErrorString = bmh_onErrorString; | ||||||
| } | ||||||
| if (bmh_onErrorString != null) { | ||||||
| try { | ||||||
| bmh_onErrorString.invokeExact(reasonCode); | ||||||
| } catch (Throwable t) { | ||||||
| // ignore | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| @Override | ||||||
| public void onError(Throwable cause) { | ||||||
| MethodHandle bmh_onErrorThrowable = this.bmh_onErrorThrowable; | ||||||
| if (bmh_onErrorThrowable == null) { | ||||||
| bmh_onErrorThrowable = findBoundHandle("onError", Throwable.class); | ||||||
| this.bmh_onErrorThrowable = bmh_onErrorThrowable; | ||||||
| } | ||||||
| if (bmh_onErrorThrowable != null) { | ||||||
| try { | ||||||
| bmh_onErrorThrowable.invokeExact(cause); | ||||||
| } catch (Throwable t) { | ||||||
| // ignore | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| @Override | ||||||
| public void onFatalError(Throwable cause) { | ||||||
| MethodHandle bmh_onFatalErrorThrowable = this.bmh_onFatalErrorThrowable; | ||||||
| if (bmh_onFatalErrorThrowable == null) { | ||||||
| bmh_onFatalErrorThrowable = findBoundHandle("onFatalError", Throwable.class); | ||||||
| this.bmh_onFatalErrorThrowable = bmh_onFatalErrorThrowable; | ||||||
| } | ||||||
| if (bmh_onFatalErrorThrowable != null) { | ||||||
| try { | ||||||
| bmh_onFatalErrorThrowable.invokeExact(cause); | ||||||
| } catch (Throwable t) { | ||||||
| // ignore | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| @Override | ||||||
| public void markIncomplete() { | ||||||
| MethodHandle bmh_markIncomplete = this.bmh_markIncomplete; | ||||||
| if (bmh_markIncomplete == null) { | ||||||
| bmh_markIncomplete = findBoundHandle("markIncomplete"); | ||||||
| this.bmh_markIncomplete = bmh_markIncomplete; | ||||||
| } | ||||||
| if (bmh_markIncomplete != null) { | ||||||
| try { | ||||||
| bmh_markIncomplete.invokeExact(); | ||||||
| } catch (Throwable t) { | ||||||
| // ignore | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| private final MethodHandle findBoundHandle(String name, Class<?> paramType) { | ||||||
| try { | ||||||
| MethodHandle virtualHandle = | ||||||
| MethodHandles.publicLookup() | ||||||
| .findVirtual( | ||||||
| bootstrapInitTelemetry.getClass(), | ||||||
| name, | ||||||
| MethodType.methodType(void.class, paramType)); | ||||||
|
|
||||||
| return virtualHandle.bindTo(bootstrapInitTelemetry); | ||||||
| } catch (NoSuchMethodException | IllegalAccessException e) { | ||||||
| return null; | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| private final MethodHandle findBoundHandle(String name) { | ||||||
| try { | ||||||
| MethodHandle virtualHandle = | ||||||
| MethodHandles.publicLookup() | ||||||
| .findVirtual( | ||||||
| bootstrapInitTelemetry.getClass(), name, MethodType.methodType(void.class)); | ||||||
|
|
||||||
| return virtualHandle.bindTo(bootstrapInitTelemetry); | ||||||
| } catch (NoSuchMethodException | IllegalAccessException e) { | ||||||
| return null; | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| package datadog.trace.bootstrap | ||
|
|
||
| import datadog.trace.test.util.DDSpecification | ||
|
|
||
| class InitializationTelemetryTest extends DDSpecification { | ||
| def "telemetry wrapper - null case"() { | ||
| expect: | ||
| InitializationTelemetry.proxy(null) == InitializationTelemetry.noOpInstance() | ||
| } | ||
|
|
||
| def "telemetry wrapper - wrap bootstrap"() { | ||
| // TODO: Figure out how to test the wrapper fully | ||
| expect: | ||
| InitializationTelemetry.proxy(new Object()) != InitializationTelemetry.noOpInstance() | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't we have a static instance for
InitializationTelemetryand use it like any other logger?It can be none/noop until to be set in the
Agent.start()or if bootstrap telemetry is wrong.It feels way more easier to use it later where we will need it rather than adding one additional parameter to every function and not setting it for
AgentCLIwill be transparent.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't really want to have a mutable static, so I decided to pass the InitializationTelemetry instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added some tests for BootstrapInitializationTelemetry. I'll add some for JsonBuffer, too.