public static ITracer Decorate( [NotNull] this ITracer source, [NotNull] TracerDecoration publicDecoration) { var decoration = publicDecoration as ITracerDecoration; var builder = new TracerDecoratorBuilder(source); // For performance, to avoid a level of indirection when not needed bool bypassBuilder = true; // Checking for null to avoid adding them if they're not implemented since the underlying library has optimizations if not subscribed if (decoration.OnSpanStarted != null) { builder = builder.OnSpanStarted(decoration.OnSpanStarted); bypassBuilder = false; } if (decoration.OnSpanFinished != null) { builder = builder.OnSpanFinished(decoration.OnSpanFinished); bypassBuilder = false; } if (decoration.OnSpanLog != null) { builder = builder.OnSpanLog(decoration.OnSpanLog); bypassBuilder = false; } if (decoration.OnSpanSetTag != null) { builder = builder.OnSpanSetTag(decoration.OnSpanSetTag); bypassBuilder = false; } if (decoration.OnSpanActivated != null) { builder = builder.OnSpanActivated(decoration.OnSpanActivated); bypassBuilder = false; } if (decoration.OnSpanStartedWithFinishCallback != null) { builder = builder.OnSpanStartedWithCallback(decoration.OnSpanStartedWithFinishCallback); bypassBuilder = false; } if (bypassBuilder) { return(source); } else { return(builder .Build()); } }
ITracer GetDecoratedTracer(string flavor) { var originalTracer = new MockTracer(); var builder = new TracerDecoratorBuilder(originalTracer); switch (flavor) { case "StartedtAndFinished": builder .OnSpanStarted((span, name) => Interlocked.Increment(ref startedSpanCount)) .OnSpanFinished((span, name) => Interlocked.Decrement(ref startedSpanCount)) ; break; case "StartedWithCallback": builder .OnSpanStartedWithCallback((span, name) => { Interlocked.Increment(ref startedSpanCount); return((s, n) => Interlocked.Decrement(ref startedSpanCount)); }) ; break; case "Both": builder .OnSpanStarted((span, name) => Interlocked.Increment(ref startedSpanCount)) .OnSpanFinished((span, name) => Interlocked.Decrement(ref startedSpanCount)) .OnSpanStartedWithCallback((span, name) => { Interlocked.Increment(ref startedSpanCount); return((s, n) => Interlocked.Decrement(ref startedSpanCount)); }) ; break; case "Five!!": for (int i = 0; i < 5; i++) { builder .OnSpanStarted((span, name) => Interlocked.Increment(ref startedSpanCount)) .OnSpanFinished((span, name) => Interlocked.Decrement(ref startedSpanCount)) ; } break; default: throw new ArgumentOutOfRangeException(nameof(flavor), flavor, "Unknown"); } return(builder.Build()); }
/// <summary> /// Would be better if we didn't need an input tracer, but there isn't a BasicTracer /// in OpenTracing for C# quite yet, and we need SOMEONE to be supplying us a working /// <see cref="IScopeManager"/> and <see cref="ISpanContext"/>. /// </summary> public static (ITracer connectedTracer, IObservable <TraceEvent> eventStream) CreateTracerEventStreamPair( ITracer tracer) { ISubject <TraceEvent> subject = new Subject <TraceEvent>(); var connectedTracer = new TracerDecoratorBuilder(tracer) .OnSpanActivated((span, operationName) => subject.OnNext(new TraceEvent.ActivatedEvent(span, operationName))) .OnSpanFinished((span, operationName) => subject.OnNext(new TraceEvent.FinishedEvent(span, operationName))) .OnSpanSetTag((span, operationName, tagKeyValue) => subject.OnNext(new TraceEvent.SetTagsEvent(span, operationName, tagKeyValue))) .OnSpanLog((span, operationName, timestamp, logKeyValues) => subject.OnNext(new TraceEvent.LogEvent(span, operationName, timestamp, logKeyValues))) //.OnSpanStarted((span, operationName) => new TraceEvent.StartedEvent()) .Build(); return(connectedTracer, eventStream : subject.AsObservable()); }
public void Test() { // jaeger tracer var originalTracer = new Tracer.Builder("Test") // DO SOME CONFIGURATION HERE .Build(); var count = 0; var tracer = new TracerDecoratorBuilder(originalTracer) .OnSpanStarted((span, name) => count++) .OnSpanActivated((span, name) => count++) .OnSpanFinished((span, name) => count++) .Build(); using (tracer.BuildSpan("test").StartActive()) { } count.ShouldBe(3); }
public void ShouldCounterSpan() { var options = OpenTracingAppMetricsDecoratorOptions.Default; var tracer = new TracerDecoratorBuilder(new MockTracer()) .WithAppMetrics(_metrics, options) .Build(); using (tracer.BuildSpan("Operation").StartActive()) { var snap = _metrics.Snapshot.Get(); var counter = snap.Contexts.Single().Counters.Single(); counter.Name.Should().Be(options.SpansCounterName); counter.Value.Count.Should().Be(1); counter.Value.Items.Single().Item.Should().Equals("Operation"); counter.Value.Items.Single().Count.Should().Equals(1); counter.Value.Items.Single().Percent.Should().Equals(100D); } using (tracer.BuildSpan("ParentSpan").StartActive()) using (tracer.BuildSpan("Childspan").StartActive()) { var snap = _metrics.Snapshot.Get(); var counter = snap.Contexts.Single().Counters.Single(); counter.Name.Should().Be(options.SpansCounterName); counter.Value.Count.Should().Be(2); counter.Value.Items.First().Item.Should().Equals("ParentSpan"); counter.Value.Items.First().Count.Should().Equals(1); counter.Value.Items.First().Percent.Should().Equals(50D); counter.Value.Items.Last().Item.Should().Equals("Childspan"); counter.Value.Items.Last().Count.Should().Equals(1); counter.Value.Items.Last().Percent.Should().Equals(50D); } { var snap = _metrics.Snapshot.Get(); var counter = snap.Contexts.Single().Counters.Single(); counter.Name.Should().Be(options.SpansCounterName); counter.Value.Count.Should().Be(0); } }
public async Task StartedWithCallbackDecorator() { var builder = new TracerDecoratorBuilder(_tracer) .OnSpanStartedWithCallback( (span, operationName) => { WriteLine($"Span started: {operationName}"); return((sp, op) => { WriteLine($"Span finished: {operationName}"); }); }) ; var decoratedTracer = builder.Build(); using (var scope = decoratedTracer.BuildSpan("main").StartActive(false)) { var span = decoratedTracer.BuildSpan("not_active").Start(); try { WriteLine("--> Doing something 1"); await Task.Delay(10); } finally { span.Finish(); } using (decoratedTracer.BuildSpan("active_child").StartActive()) { await Task.Delay(10); WriteLine("--> Doing something 2"); } scope.Span.Finish(); } }
public async Task WriteSomeSpanStory() { var builder = new TracerDecoratorBuilder(_tracer) .OnSpanStarted((span, operationName) => WriteLine($"Started: {operationName}")) .OnSpanActivated((span, operationName) => WriteLine($"Activated: {operationName}")) .OnSpanFinished((span, operationName) => WriteLine($"Finished: {operationName}")) .OnSpanLog((span, operationName, timestamp, fields) => { WriteLine($"Log: {operationName} : {string.Join(", ", fields.Select(f => $"{f.key}/{f.value}"))}"); }) .OnSpanSetTag((span, operationName, tag) => { WriteLine($"Tag: {operationName} : {tag.key}/{tag.value}"); }); ; var decoratedTracer = builder.Build(); using (var scope = decoratedTracer .BuildSpan("main") .WithTag("tag1", 1) .StartActive(false) ) { scope.Span.SetTag("tag2", 2); var span = decoratedTracer.BuildSpan("not_active").Start(); try { WriteLine("--> Doing something 1"); span.SetTag("tag3", true); await Task.Delay(10); } finally { span.Finish(); } using (decoratedTracer.BuildSpan("active_child").StartActive()) { decoratedTracer.ActiveSpan.Log(new Dictionary <string, object> { { "log1", 42 }, { "log2", "test" } }); await Task.Delay(10); WriteLine("--> Doing something 2"); } scope.Span.Finish(); } var lines = new[] { "Started: main", "Tag: main : tag1/1", "Activated: main", "Tag: main : tag2/2", "Started: not_active", @"--> Doing something 1", "Tag: not_active : tag3/True", "Finished: not_active", "Started: active_child", "Activated: active_child", "Log: active_child : log1/42, log2/test", @"--> Doing something 2", "Finished: active_child", "Finished: main", }; _outputs.Count.ShouldBe(lines.Length); for (int i = 0; i < lines.Length; i++) { _outputs[i].ShouldBe(lines[i]); } }
private static TracerDecoratorBuilder WithAppMetrics(this TracerDecoratorBuilder builder, IMetrics metrics, OpenTracingAppMetricsDecoratorOptions options, Action <OpenTracingAppMetricsDecoratorOptions> setupOptions) { options = options ?? throw new ArgumentNullException(nameof(options)); setupOptions?.Invoke(options); if (options.SpansCountersEnabled) { var spansCounter = new CounterOptions { Name = options.SpansCounterName }; builder.OnSpanStarted((span, operationName) => { metrics.Measure.Counter.Increment(spansCounter, operationName); if (options.DistinctOperationsCountersEnabled) { var distinctCounter = new CounterOptions { Name = options.DistinctOperationCountersName + operationName }; metrics.Measure.Counter.Increment(distinctCounter); } }); builder.OnSpanFinished((span, operationName) => { metrics.Measure.Counter.Decrement(spansCounter, operationName); if (options.DistinctOperationsCountersEnabled) { var distinctCounter = new CounterOptions { Name = options.DistinctOperationCountersName + operationName }; metrics.Measure.Counter.Decrement(distinctCounter); } }); } if (options.SpansMetersEnabled) { var spansMeter = new MeterOptions { Name = options.SpansMeterName }; builder.OnSpanStarted((span, operationName) => { metrics.Measure.Meter.Mark(spansMeter, operationName); if (options.DistinctOperationsMetersEnabled) { var distinctMeter = new MeterOptions { Name = options.DistinctOperationMetersName + operationName }; metrics.Measure.Meter.Mark(distinctMeter); } }); } if (options.SpansTimersEnabled) { var spansTimer = new TimerOptions { Name = options.SpansTimerName, DurationUnit = TimeUnit.Milliseconds, RateUnit = TimeUnit.Milliseconds }; builder.OnSpanStartedWithCallback((span, operationName) => { var timerContext = metrics.Measure.Timer.Time(spansTimer, operationName); TimerContext distinctTimerContext = default(TimerContext); if (options.DistinctOperationsTimersEnabled) { var distinctTimer = new TimerOptions { Name = options.DistinctOperationTimersName + operationName, DurationUnit = TimeUnit.Milliseconds, RateUnit = TimeUnit.Milliseconds }; distinctTimerContext = metrics.Measure.Timer.Time(distinctTimer); } return((sp, op) => { timerContext.Dispose(); distinctTimerContext.Dispose(); }); }); } return(builder); }
public static TracerDecoratorBuilder WithAppMetrics(this TracerDecoratorBuilder builder, IMetrics metrics, OpenTracingAppMetricsDecoratorOptions options) => WithAppMetrics(builder, metrics, options, opts => { });
public static TracerDecoratorBuilder WithAppMetrics(this TracerDecoratorBuilder builder, IMetrics metrics, bool allEnabled = true, Action <OpenTracingAppMetricsDecoratorOptions> setupOptions = null) => WithAppMetrics(builder, metrics, OpenTracingAppMetricsDecoratorOptions.Default, setupOptions ?? (opts => { }));