-
Notifications
You must be signed in to change notification settings - Fork 232
Conversation
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.
Thanks for your contribution! Before we accept it, however, you'd need to sign-off your commit, as part of the "DCO" (https://github.com/probot/dco#how-it-works).
You can do that by running git commit --amend -s
and force-pushing the commit (git push --force
). This will get this PR updated.
@@ -206,6 +206,11 @@ public synchronized JaegerSpan setTag(String key, Number value) { | |||
} | |||
|
|||
private JaegerSpan setTagAsObject(String key, Object value) { | |||
if (finished) { | |||
log.warn("Span has already been finished; cannot set tag.", new RuntimeException("Called from:")); |
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.
Do you have a sample output for this log message? I'm not sure creating a new exception here (even if not throwing it) is what we want...
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 think this is useful otherwise debugging this will be very hard in a large code base.
09:25:12.802 [Test worker] WARN io.jaegertracing.JaegerSpan - Span has already been finished; cannot set tag.
java.lang.RuntimeException: Called from:
at io.jaegertracing.JaegerSpan.setTagAsObject(JaegerSpan.java:210)
at io.jaegertracing.JaegerSpan.setTag(JaegerSpan.java:195)
at io.jaegertracing.JaegerSpanTest.testSetStringTagAfterFinish(JaegerSpanTest.java:141)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:106)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:38)
at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:66)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
at sun.reflect.GeneratedMethodAccessor34.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
at com.sun.proxy.$Proxy1.processTestClass(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:109)
at sun.reflect.GeneratedMethodAccessor33.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
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 can, of course, remove the exception. For my use case, providing the stack trace will make it much easier to hunt down these errors.
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.
Exception seems useful, but dual-finish doesn't use it currently, so if we want to have exception, I'd say it should be a tracer config switch to enable it.
If we are making this change for tags, it should also apply for all methods that write to the span, i.e. setOperation, log(), etc.
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 do agree that the exception seems useful, but I'd rather have two log entries then. One at warning level, with a message like "Cannot set tag, as the span is already closed. Set log level to debug for information about the caller". Then, the second would be in debug level, wrapped in if (log.isDebugEnabled()) { logger.debug(...); }
, with the stack trace.
My concerns are:
- Pollute the logs with stack traces
- Confuse users into thinking these stack traces are actual exceptions
- Wasted resources in collecting the stack trace for every single time the span is closed, as this information is useful only once per caller.
70b9c76
to
1c66558
Compare
Before I actually test the logging (because it's sort of annoying to test that...) does this look good? |
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.
looks reasonable
@@ -536,6 +540,11 @@ public Builder withExpandExceptionLogs() { | |||
return this; | |||
} | |||
|
|||
public Builder withLoggingStackTraces() { |
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.
LoggingStackTraces name might be confused with some more serious feature. I would rename to withLogStackTraceOnWarnings
.
Also add javadoc explaining the option.
log.warn("Span has already been finished; cannot log."); | ||
} | ||
return this; | ||
} |
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 suggest to DRY it by moving this to a method spanAlreadyFinished(String funcName)
and then replacing the checks with
if (spanAlreadyFinished("setTag")) {
return this;
}
c683b7e
to
5eb07b0
Compare
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.
Other than the concerns I listed regarding adding the stack trace to a warn level, this does LGTM.
@jpkrohling suggestion is way better & simpler than mine of doing a custom flag. |
Changed it to do two lines when debug is on. |
@@ -99,6 +99,10 @@ public JaegerTracer getTracer() { | |||
@Override | |||
public JaegerSpan setOperationName(String operationName) { | |||
synchronized (this) { | |||
if (spanAlreadyFinished("set baggage item")) { |
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.
set operation name
@@ -132,6 +136,10 @@ public JaegerSpan setBaggageItem(String key, String value) { | |||
return this; | |||
} | |||
synchronized (this) { | |||
if (spanAlreadyFinished("set baggage item")) { |
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.
strictly speaking setting baggage would work even after the span is finished
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.
It seems unlikely that the user would intend to do this, but do you want me to remove it?
9640ec7
to
c24752e
Compare
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.
LGTM. I have a couple of very minor comments and it's up to you to fix them on this PR or not.
Thank you very much for your contribution!
|
||
@Test | ||
public void testLogWithTimestampAfterFinish() { | ||
Map<String, String> unexpectedFields = new HashMap<String, String>() { |
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.
It's cleaner to use Collections.singletonMap("foo", "bar")
in this case.
@Test | ||
public void testNoLoggingingStackTracesOnDebug() { | ||
log.setEnabledLevels(Level.WARN); | ||
JaegerSpan jaegerSpan = (JaegerSpan)tracer.buildSpan("foo").start(); |
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 just got a PR merged yesterday that makes this cast unnecessary. Could you rebase your PR and check it?
@Test | ||
public void testLoggingingStackTracesOnDebug() { | ||
log.setEnabledLevels(Level.WARN, Level.DEBUG); | ||
JaegerSpan jaegerSpan = (JaegerSpan)tracer.buildSpan("foo").start(); |
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.
Same as the previous comment.
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.
There have to be a few more changes for this to be possible (buildSpan has to return a JaegerTracer.SpanBuilder
, and SpanBuilder
needs to be public.
I'll make these changes, but I don't know if you want to do that in a separate diff
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.
No no, just rebase to the latest master. Those changes are already there :)
Do more logging on debug levels. Signed-off-by: Nikhil Bysani <nikhil.bysani@signifyd.com>
53b89dc
to
5c6d8a5
Compare
Which problem is this PR solving?
If you set the tag after the span finishes, this can cause a race condition in the sender as it tries to iterate over the tag map.
To fix that, you really shouldn't even be able to set a tag after the span finishes.
Short description of the changes
Check finish on setTagAsObject and return if the span is already finished.