Skip to content

Commit 7c5d817

Browse files
committed
Add debug flag to kamon.tracing
When enabled, will warn when trying to change closed spans
1 parent 28cdeac commit 7c5d817

File tree

2 files changed

+130
-53
lines changed

2 files changed

+130
-53
lines changed

core/kamon-core/src/main/resources/reference.conf

+5-1
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,10 @@ kamon {
263263
# look for PreFinish hooks on the current Context and apply them if available.
264264
pre-finish = []
265265
}
266+
267+
# Enables warning messages when trying to change closed spans.
268+
# e.g. all operations an Empty, Remote and finished Local spans.
269+
debug = false
266270
}
267271

268272
propagation {
@@ -373,4 +377,4 @@ kamon {
373377
}
374378
}
375379
}
376-
}
380+
}

core/kamon-core/src/main/scala/kamon/trace/Span.scala

+125-52
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ package kamon
1818
package trace
1919

2020
import java.time.{Duration, Instant}
21-
2221
import kamon.context.Context
2322
import kamon.tag.TagSet
2423
import kamon.trace.Span.Link
24+
import kamon.trace.Span.Local._logger
2525
import kamon.trace.Trace.SamplingDecision
2626
import kamon.util.Clock
2727
import org.slf4j.LoggerFactory
@@ -77,6 +77,10 @@ sealed abstract class Span extends Sampler.Operation {
7777
*/
7878
def trace: Trace
7979

80+
/**
81+
* Returns true if this Span was finished.
82+
*/
83+
8084
/**
8185
* Returns true if this Span was initially created in another process and then transferred to this process.
8286
*/
@@ -225,7 +229,7 @@ sealed abstract class Span extends Sampler.Operation {
225229

226230
}
227231

228-
object Span {
232+
object Span extends Configuration {
229233

230234
/**
231235
* Key used to store and retrieve Span instances from the Context
@@ -417,6 +421,7 @@ object Span {
417421
private var _trackMetrics: Boolean = initialTrackMetrics
418422
private var _trackDelayedSpanMetrics: Boolean = true
419423
private var _isOpen: Boolean = true
424+
private var _debug: Boolean = config().getBoolean("kamon.trace.debug")
420425
private var _hasError: Boolean = false
421426
private var _operationName: String = initialOperationName
422427
private var _marks: List[Mark] = initialMarks
@@ -435,55 +440,81 @@ object Span {
435440
_startedAt = at
436441
_isDelayedStarted = true
437442
mark(MarkKeys.SpanStarted, at)
438-
}
443+
} else if (warnOnClosed)
444+
_logger.warn(s"Cannot start finished span with name: ${_operationName}")
439445
this
440446
}
441447

442448
override def tag(key: String, value: String): Span = synchronized {
443-
if(isSampled && _isOpen)
449+
if(isSampled && _isOpen) {
444450
_spanTags.add(key, value)
451+
} else if (warnOnClosed) {
452+
_logger.warn(s"Cannot apply tag: Tag(${key}, ${value}) to finished span with name: ${_operationName}")
453+
}
445454
this
446455
}
447456

448457
override def tag(key: String, value: Long): Span = synchronized {
449-
if(isSampled && _isOpen)
458+
if(isSampled && _isOpen) {
450459
_spanTags.add(key, value)
460+
} else if (warnOnClosed) {
461+
_logger.warn(s"Cannot apply tag: Tag(${key}, ${value}) to finished span with name: ${_operationName}")
462+
}
451463
this
452464
}
453465

454466
override def tag(key: String, value: Boolean): Span = synchronized {
455-
if(isSampled && _isOpen)
467+
if(isSampled && _isOpen) {
456468
_spanTags.add(key, value)
469+
} else if (warnOnClosed) {
470+
_logger.warn(s"Cannot apply tag: Tag(${key}, ${value}) to finished span with name: ${_operationName}")
471+
}
457472
this
458473
}
459474

460475
override def tag(tags: TagSet): Span = synchronized {
461-
if(isSampled && _isOpen)
476+
if(isSampled && _isOpen) {
462477
_spanTags.add(tags)
478+
} else if (warnOnClosed) {
479+
_logger.warn(s"Cannot apply tags: ${tags} to finished span with name: ${_operationName}")
480+
}
463481
this
464482
}
465483

466484
override def tagMetrics(key: String, value: String): Span = synchronized {
467-
if(_isOpen && _trackMetrics)
485+
if(_isOpen && _trackMetrics) {
468486
_metricTags.add(key, value)
487+
} else if (warnOnClosed) {
488+
_logger.warn(s"Cannot apply metric: Metric(${key}, ${value}) to finished span with name: ${_operationName}")
489+
}
469490
this
470491
}
471492

472493
override def tagMetrics(key: String, value: Long): Span = synchronized {
473-
if(_isOpen && _trackMetrics)
494+
if(_isOpen && _trackMetrics) {
474495
_metricTags.add(key, value)
475-
this
496+
} else if (warnOnClosed) {
497+
_logger.warn(s"Cannot apply metric: Metric(${key}, ${value}) to finished span with name: ${_operationName}")
498+
}
499+
this
476500
}
477501

478502
override def tagMetrics(key: String, value: Boolean): Span = synchronized {
479-
if(_isOpen && _trackMetrics)
503+
if(_isOpen && _trackMetrics) {
480504
_metricTags.add(key, value)
505+
} else if (warnOnClosed) {
506+
_logger.warn(s"Cannot apply metric: Metric(${key}, ${value}) to finished span with name: ${_operationName}")
507+
}
508+
481509
this
482510
}
483511

484512
override def tagMetrics(tags: TagSet): Span = synchronized {
485-
if(_isOpen && _trackMetrics)
513+
if(_isOpen && _trackMetrics) {
486514
_metricTags.add(tags)
515+
} else if (warnOnClosed) {
516+
_logger.warn(s"Cannot apply tag metrics: ${tags} to finished span with name: ${_operationName}")
517+
}
487518
this
488519
}
489520

@@ -492,14 +523,21 @@ object Span {
492523
}
493524

494525
override def mark(key: String, at: Instant): Span = synchronized {
495-
if(_isOpen)
526+
if(_isOpen) {
496527
_marks = Mark(at, key) :: _marks
528+
} else if (warnOnClosed) {
529+
_logger.warn(s"Cannot apply mark: Mark(${key}, ${at}) to finished span with name: ${_operationName}")
530+
}
497531
this
498532
}
499533

500534
override def link(span: Span, kind: Link.Kind): Span = synchronized {
501-
if(_isOpen)
535+
if(_isOpen) {
502536
_links = Link(kind, span.trace, span.id) :: _links
537+
} else if (warnOnClosed) {
538+
_logger.warn(s"Cannot link span ${span.operationName()} to finished span with name: ${_operationName}")
539+
}
540+
503541
this
504542
}
505543

@@ -509,6 +547,8 @@ object Span {
509547

510548
if(isSampled)
511549
_spanTags.add(TagKeys.ErrorMessage, message)
550+
} else if (warnOnClosed) {
551+
_logger.warn(s"Cannot fail finished span with name: ${_operationName}")
512552
}
513553
this
514554
}
@@ -523,6 +563,8 @@ object Span {
523563
if(includeErrorStacktrace)
524564
_spanTags.add(TagKeys.ErrorStacktrace, toStackTraceString(throwable))
525565
}
566+
} else if (warnOnClosed) {
567+
_logger.warn(s"Cannot fail finished span with name: ${_operationName}")
526568
}
527569
this
528570
}
@@ -537,7 +579,10 @@ object Span {
537579
if(includeErrorStacktrace)
538580
_spanTags.add(TagKeys.ErrorStacktrace, toStackTraceString(throwable))
539581
}
582+
} else if (warnOnClosed) {
583+
_logger.warn(s"Cannot fail finished span with name: ${_operationName}")
540584
}
585+
541586
this
542587
}
543588

@@ -578,8 +623,12 @@ object Span {
578623
}
579624

580625
override def name(operationName: String): Span = synchronized {
581-
if(_isOpen)
626+
if(_isOpen) {
582627
_operationName = operationName
628+
} else if (warnOnClosed) {
629+
_logger.warn(s"Cannot name finished span with name: ${_operationName}")
630+
}
631+
583632
this
584633
}
585634

@@ -608,7 +657,14 @@ object Span {
608657
val finalMetricTags = createMetricTags()
609658
recordSpanMetrics(finishedAt, finalMetricTags)
610659
reportSpan(finishedAt, finalMetricTags)
660+
} else if (warnOnClosed) {
661+
_logger.warn(s"Cannot finish already finished span with name: ${_operationName}")
611662
}
663+
664+
}
665+
666+
private def warnOnClosed = {
667+
_debug && !_isOpen
612668
}
613669

614670
private def isSampled: Boolean =
@@ -667,7 +723,6 @@ object Span {
667723
object Local {
668724
private val _logger = LoggerFactory.getLogger(classOf[Span.Local])
669725
}
670-
671726
/**
672727
* A immutable, no-op Span that can be used to signal that there is no Span information. An empty Span completely
673728
* ignores all writes made to it.
@@ -680,29 +735,38 @@ object Span {
680735
override def isRemote: Boolean = false
681736
override def isEmpty: Boolean = true
682737
override def position(): Position = Position.Unknown
683-
override def tag(key: String, value: String): Span = this
684-
override def tag(key: String, value: Long): Span = this
685-
override def tag(key: String, value: Boolean): Span = this
686-
override def tag(tagSet: TagSet): Span = this
687-
override def tagMetrics(key: String, value: String): Span = this
688-
override def tagMetrics(key: String, value: Long): Span = this
689-
override def tagMetrics(key: String, value: Boolean): Span = this
690-
override def tagMetrics(tagSet: TagSet): Span = this
691-
override def mark(key: String): Span = this
692-
override def mark(key: String, at: Instant): Span = this
693-
override def link(span: Span, kind: Link.Kind): Span = this
694-
override def fail(errorMessage: String): Span = this
695-
override def fail(cause: Throwable): Span = this
696-
override def fail(errorMessage: String, cause: Throwable): Span = this
697-
override def name(name: String): Span = this
738+
override def tag(key: String, value: String): Span = warnAndDiscard()
739+
override def tag(key: String, value: Long): Span = warnAndDiscard()
740+
override def tag(key: String, value: Boolean): Span = warnAndDiscard()
741+
override def tag(tagSet: TagSet): Span = warnAndDiscard()
742+
override def tagMetrics(key: String, value: String): Span = warnAndDiscard()
743+
override def tagMetrics(key: String, value: Long): Span = warnAndDiscard()
744+
override def tagMetrics(key: String, value: Boolean): Span = warnAndDiscard()
745+
override def tagMetrics(tagSet: TagSet): Span = warnAndDiscard()
746+
override def mark(key: String): Span = warnAndDiscard()
747+
override def mark(key: String, at: Instant): Span = warnAndDiscard()
748+
override def link(span: Span, kind: Link.Kind): Span = warnAndDiscard()
749+
override def fail(errorMessage: String): Span = warnAndDiscard()
750+
override def fail(cause: Throwable): Span = warnAndDiscard()
751+
override def fail(errorMessage: String, cause: Throwable): Span = warnAndDiscard()
752+
override def name(name: String): Span = warnAndDiscard()
698753
override def trackMetrics(): Span = this
699754
override def doNotTrackMetrics(): Span = this
700755
override def takeSamplingDecision(): Span = this
701-
override def finish(): Unit = {}
702-
override def finish(at: Instant): Unit = {}
703-
override def finishAfter(duration: Duration): Unit = {}
756+
override def finish(): Unit = { warnAndDiscard(); {}}
757+
override def finish(at: Instant): Unit = { warnAndDiscard(); {}}
758+
override def finishAfter(duration: Duration): Unit = { warnAndDiscard(); {}}
704759
override def operationName(): String = "empty"
705760
override def toString(): String = "Span.Empty"
761+
762+
private val _logger = LoggerFactory.getLogger(classOf[Span])
763+
private def _debug: Boolean = config().getBoolean("kamon.trace.debug")
764+
private def warnAndDiscard(): Span = {
765+
if (_debug) {
766+
_logger.debug("Cannot perform operations on Empty spans.")
767+
}
768+
this
769+
}
706770
}
707771

708772

@@ -716,29 +780,38 @@ object Span {
716780
override def isRemote: Boolean = true
717781
override def isEmpty: Boolean = false
718782
override def position(): Position = Position.Unknown
719-
override def tag(key: String, value: String): Span = this
720-
override def tag(key: String, value: Long): Span = this
721-
override def tag(key: String, value: Boolean): Span = this
722-
override def tag(tagSet: TagSet): Span = this
723-
override def tagMetrics(key: String, value: String): Span = this
724-
override def tagMetrics(key: String, value: Long): Span = this
725-
override def tagMetrics(key: String, value: Boolean): Span = this
726-
override def tagMetrics(tagSet: TagSet): Span = this
727-
override def mark(key: String): Span = this
728-
override def mark(key: String, at: Instant): Span = this
729-
override def link(span: Span, kind: Link.Kind): Span = this
730-
override def fail(errorMessage: String): Span = this
731-
override def fail(cause: Throwable): Span = this
732-
override def fail(errorMessage: String, cause: Throwable): Span = this
733-
override def name(name: String): Span = this
783+
override def tag(key: String, value: String): Span = warnAndDiscard()
784+
override def tag(key: String, value: Long): Span = warnAndDiscard()
785+
override def tag(key: String, value: Boolean): Span = warnAndDiscard()
786+
override def tag(tagSet: TagSet): Span = warnAndDiscard()
787+
override def tagMetrics(key: String, value: String): Span = warnAndDiscard()
788+
override def tagMetrics(key: String, value: Long): Span = warnAndDiscard()
789+
override def tagMetrics(key: String, value: Boolean): Span = warnAndDiscard()
790+
override def tagMetrics(tagSet: TagSet): Span = warnAndDiscard()
791+
override def mark(key: String): Span = warnAndDiscard()
792+
override def mark(key: String, at: Instant): Span = warnAndDiscard()
793+
override def link(span: Span, kind: Link.Kind): Span = warnAndDiscard()
794+
override def fail(errorMessage: String): Span = warnAndDiscard()
795+
override def fail(cause: Throwable): Span = warnAndDiscard()
796+
override def fail(errorMessage: String, cause: Throwable): Span = warnAndDiscard()
797+
override def name(name: String): Span = warnAndDiscard()
734798
override def trackMetrics(): Span = this
735799
override def doNotTrackMetrics(): Span = this
736800
override def takeSamplingDecision(): Span = this
737-
override def finish(): Unit = {}
738-
override def finish(at: Instant): Unit = {}
739-
override def finishAfter(duration: Duration): Unit = {}
801+
override def finish(): Unit = { warnAndDiscard(); {}}
802+
override def finish(at: Instant): Unit = { warnAndDiscard(); {}}
803+
override def finishAfter(duration: Duration): Unit = { warnAndDiscard(); {}}
740804
override def operationName(): String = "empty"
741805
override def toString(): String = s"Span.Remote{id=${id.string},parentId=${parentId.string},trace=${trace}"
806+
807+
private val _logger = LoggerFactory.getLogger(classOf[Span.Remote])
808+
private def _debug: Boolean = config().getBoolean("kamon.trace.debug")
809+
private def warnAndDiscard(): Span = {
810+
if (_debug) {
811+
_logger.debug("Cannot perform operations on Remote spans.")
812+
}
813+
this
814+
}
742815
}
743816

744817

0 commit comments

Comments
 (0)