diff --git a/samples/Exporters/TestApplicationInsights.cs b/samples/Exporters/TestApplicationInsights.cs index d6b4b47af55..315af97fa5a 100644 --- a/samples/Exporters/TestApplicationInsights.cs +++ b/samples/Exporters/TestApplicationInsights.cs @@ -63,9 +63,9 @@ internal static object Run() Stats.ViewManager.RegisterView(VideoSizeView); - using (var scopedTags = tagContextBuilder.BuildScoped()) + using (tagContextBuilder.BuildScoped()) { - using (var scopedSpan = spanBuilder.StartScopedSpan()) + using (Tracer.WithSpan(spanBuilder.StartSpan())) { Tracer.CurrentSpan.AddEvent("Start processing video."); Thread.Sleep(TimeSpan.FromMilliseconds(10)); diff --git a/samples/Exporters/TestHttpClient.cs b/samples/Exporters/TestHttpClient.cs index eec1f62077f..4e2ed713abb 100644 --- a/samples/Exporters/TestHttpClient.cs +++ b/samples/Exporters/TestHttpClient.cs @@ -31,29 +31,29 @@ internal static object Run() { Console.WriteLine("Hello World!"); - var collector = new DependenciesCollector(new DependenciesCollectorOptions(), Tracer, Samplers.AlwaysSample); - - var exporter = new ZipkinTraceExporter( - new ZipkinTraceExporterOptions() + using (new DependenciesCollector(new DependenciesCollectorOptions(), Tracer, Samplers.AlwaysSample)) + { + var exporter = new ZipkinTraceExporter( + new ZipkinTraceExporterOptions() + { + Endpoint = new Uri("https://zipkin.azurewebsites.net/api/v2/spans"), + ServiceName = typeof(Program).Assembly.GetName().Name, + }, + Tracing.ExportComponent); + exporter.Start(); + + using (Tracer.WithSpan(Tracer.SpanBuilder("incoming request").SetSampler(Samplers.AlwaysSample).StartSpan())) { - Endpoint = new Uri("https://zipkin.azurewebsites.net/api/v2/spans"), - ServiceName = typeof(Program).Assembly.GetName().Name, - }, - Tracing.ExportComponent); - exporter.Start(); - - var scope = Tracer.SpanBuilder("incoming request").SetSampler(Samplers.AlwaysSample).StartScopedSpan(); - - var client = new HttpClient(); - var t = client.GetStringAsync("http://bing.com"); - - t.Wait(); - - scope.Dispose(); + using (var client = new HttpClient()) + { + client.GetStringAsync("http://bing.com").GetAwaiter().GetResult(); + } + } - Console.ReadLine(); + Console.ReadLine(); - return null; + return null; + } } } } diff --git a/samples/Exporters/TestRedis.cs b/samples/Exporters/TestRedis.cs index 72c5ab7cd77..b0787ae317a 100644 --- a/samples/Exporters/TestRedis.cs +++ b/samples/Exporters/TestRedis.cs @@ -61,7 +61,7 @@ internal static object Run(string zipkinUri) var db = connection.GetDatabase(); // 4. Create a scoped span. It will end automatically when using statement ends - using (var scope = tracer.SpanBuilder("Main").StartScopedSpan()) + using (tracer.WithSpan(tracer.SpanBuilder("Main").StartSpan())) { Console.WriteLine("About to do a busy work"); for (var i = 0; i < 10; i++) @@ -84,7 +84,7 @@ private static void DoWork(IDatabase db) // 7. Start another span. If another span was already started, it'll use that span as the parent span. // In this example, the main method already started a span, so that'll be the parent span, and this will be // a child span. - using (var scope = tracer.SpanBuilder("DoWork").StartScopedSpan()) + using (tracer.WithSpan(tracer.SpanBuilder("DoWork").StartSpan())) { // Simulate some work. var span = tracer.CurrentSpan; diff --git a/samples/Exporters/TestStackdriver.cs b/samples/Exporters/TestStackdriver.cs index 802a1844754..97bff278763 100644 --- a/samples/Exporters/TestStackdriver.cs +++ b/samples/Exporters/TestStackdriver.cs @@ -64,9 +64,9 @@ internal static object Run(string projectId) Stats.ViewManager.RegisterView(VideoSizeView); - using (var scopedTags = tagContextBuilder.BuildScoped()) + using (tagContextBuilder.BuildScoped()) { - using (var scopedSpan = spanBuilder.StartScopedSpan()) + using (Tracer.WithSpan(spanBuilder.StartSpan())) { Tracer.CurrentSpan.AddEvent("Processing video."); Thread.Sleep(TimeSpan.FromMilliseconds(10)); diff --git a/samples/Exporters/TestZipkin.cs b/samples/Exporters/TestZipkin.cs index f9912ffb5a9..3e898b85354 100644 --- a/samples/Exporters/TestZipkin.cs +++ b/samples/Exporters/TestZipkin.cs @@ -50,7 +50,7 @@ internal static object Run(string zipkinUri) var tracer = Tracing.Tracer; // 4. Create a scoped span. It will end automatically when using statement ends - using (var scope = tracer.SpanBuilder("Main").StartScopedSpan()) + using (tracer.WithSpan(tracer.SpanBuilder("Main").StartSpan())) { Console.WriteLine("About to do a busy work"); for (var i = 0; i < 10; i++) @@ -73,7 +73,7 @@ private static void DoWork(int i) // 7. Start another span. If another span was already started, it'll use that span as the parent span. // In this example, the main method already started a span, so that'll be the parent span, and this will be // a child span. - using (var scope = tracer.SpanBuilder("DoWork").StartScopedSpan()) + using (tracer.WithSpan(tracer.SpanBuilder("DoWork").StartSpan())) { // Simulate some work. var span = tracer.CurrentSpan; diff --git a/src/OpenTelemetry.Abstractions/Context/Propagation/TraceContextFormat.cs b/src/OpenTelemetry.Abstractions/Context/Propagation/TraceContextFormat.cs index ed8baad6f3b..f8042318847 100644 --- a/src/OpenTelemetry.Abstractions/Context/Propagation/TraceContextFormat.cs +++ b/src/OpenTelemetry.Abstractions/Context/Propagation/TraceContextFormat.cs @@ -50,7 +50,7 @@ public SpanContext Extract(T carrier, Func> ge if (traceparentCollection.Count() > 1) { // multiple traceparent are not allowed - return null; + return SpanContext.Blank; } var traceparent = traceparentCollection?.FirstOrDefault(); @@ -58,7 +58,7 @@ public SpanContext Extract(T carrier, Func> ge if (!traceparentParsed) { - return null; + return SpanContext.Blank; } var tracestateResult = Tracestate.Empty; @@ -159,7 +159,7 @@ public SpanContext Extract(T carrier, Func> ge } // in case of exception indicate to upstream that there is no parseable context from the top - return null; + return SpanContext.Blank; } /// diff --git a/src/OpenTelemetry.Abstractions/Internal/BlankSpan.cs b/src/OpenTelemetry.Abstractions/Internal/BlankSpan.cs new file mode 100644 index 00000000000..3d76ff39573 --- /dev/null +++ b/src/OpenTelemetry.Abstractions/Internal/BlankSpan.cs @@ -0,0 +1,169 @@ +// +// Copyright 2018, OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +namespace OpenTelemetry.Trace +{ + using System; + using System.Collections.Generic; + + /// + /// Blank span. + /// + public sealed class BlankSpan : ISpan + { + /// + /// Blank span instance. + /// + public static readonly BlankSpan Instance = new BlankSpan(); + + private BlankSpan() + { + } + + /// + public SpanContext Context => SpanContext.Blank; + + /// + public bool IsRecordingEvents => false; + + /// + public Status Status + { + get => Status.Ok; + + set + { + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + } + } + + /// + public bool HasEnded { get; } + + /// + public void UpdateName(string name) + { + if (name == null) + { + throw new ArgumentNullException(nameof(name)); + } + } + + /// + public void SetAttribute(string key, IAttributeValue value) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + } + + /// + public void SetAttribute(string key, string value) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + } + + /// + public void SetAttribute(string key, long value) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + } + + /// + public void SetAttribute(string key, double value) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + } + + /// + public void SetAttribute(string key, bool value) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + } + + /// + public void AddEvent(string name) + { + if (name == null) + { + throw new ArgumentNullException(nameof(name)); + } + } + + /// + public void AddEvent(string name, IDictionary attributes) + { + if (name == null) + { + throw new ArgumentNullException(nameof(name)); + } + + if (attributes == null) + { + throw new ArgumentNullException(nameof(attributes)); + } + } + + /// + public void AddEvent(IEvent newEvent) + { + if (newEvent == null) + { + throw new ArgumentNullException(nameof(newEvent)); + } + } + + /// + public void AddLink(ILink link) + { + if (link == null) + { + throw new ArgumentNullException(nameof(link)); + } + } + + /// + public void End() + { + } + } +} diff --git a/src/OpenTelemetry.Abstractions/Trace/ISampler.cs b/src/OpenTelemetry.Abstractions/Trace/ISampler.cs index eac86f18788..9b97f960051 100644 --- a/src/OpenTelemetry.Abstractions/Trace/ISampler.cs +++ b/src/OpenTelemetry.Abstractions/Trace/ISampler.cs @@ -37,10 +37,10 @@ public interface ISampler /// Name of a span to be created. Note, that the name of the span is settable. /// So this name can be changed later and implementation should assume that. /// Typical example of a name change is when representing incoming http request - /// has a name of url path and then being updated with route name when rouing complete. + /// has a name of url path and then being updated with route name when routing complete. /// - /// Links associated with the parent span. + /// Links associated with the span. /// True of span needs to be created. False otherwise. - bool ShouldSample(SpanContext parentContext, TraceId traceId, SpanId spanId, string name, IEnumerable parentLinks); + bool ShouldSample(SpanContext parentContext, TraceId traceId, SpanId spanId, string name, IEnumerable links); } } diff --git a/src/OpenTelemetry.Abstractions/Trace/ISpan.cs b/src/OpenTelemetry.Abstractions/Trace/ISpan.cs index ac8991e90aa..edad4cd84d3 100644 --- a/src/OpenTelemetry.Abstractions/Trace/ISpan.cs +++ b/src/OpenTelemetry.Abstractions/Trace/ISpan.cs @@ -20,7 +20,7 @@ namespace OpenTelemetry.Trace /// /// Span represents the execution of the certain span of code or span of time between two events which is part of - /// a distributed trace and has result of execution, context of executuion and other properties. + /// a distributed trace and has result of execution, context of execution and other properties. /// /// This class is mostly write only. Span should not be used to exchange information. Only to add properties /// to it for monitoring purposes. It will be converted to SpanData that is readable. @@ -103,7 +103,7 @@ public interface ISpan /// Adds a single with the attributes to the . /// /// Event name. - /// of attributes name/value pairs associted with the . + /// of attributes name/value pairs associated with the . void AddEvent(string name, IDictionary attributes); /// diff --git a/src/OpenTelemetry.Abstractions/Trace/ISpanBuilder.cs b/src/OpenTelemetry.Abstractions/Trace/ISpanBuilder.cs index 389b0662724..9f89a5d88f3 100644 --- a/src/OpenTelemetry.Abstractions/Trace/ISpanBuilder.cs +++ b/src/OpenTelemetry.Abstractions/Trace/ISpanBuilder.cs @@ -17,7 +17,6 @@ namespace OpenTelemetry.Trace { using System.Collections.Generic; - using OpenTelemetry.Context; /// /// Span builder. @@ -32,38 +31,68 @@ public interface ISpanBuilder ISpanBuilder SetSampler(ISampler sampler); /// - /// Set the parent links on the span. + /// Sets the to use as a parent for the new span. + /// Any parent that was set previously will be discarded. /// - /// Parent links to set on span. + /// to set. /// This span builder for chaining. - ISpanBuilder SetParentLinks(IEnumerable parentLinks); + ISpanBuilder SetParent(ISpan parent); /// - /// Set the record events value. + /// Sets the remote to use as a parent for the new span. + /// Any parent that was set previously will be discarded. /// - /// Value indicating whether to record span. + /// to set. /// This span builder for chaining. - ISpanBuilder SetRecordEvents(bool recordEvents); + ISpanBuilder SetParent(SpanContext remoteParent); /// - /// Starts the span. + /// Makes the result span to become a root for a new trace. + /// Any parent that was set previously will be discarded. /// - /// Span that was just started. - ISpan StartSpan(); + /// This span builder for chaining. + ISpanBuilder SetNoParent(); + + /// + /// Set on the span. + /// + /// to set. + /// This span builder for chaining. + ISpanBuilder SetSpanKind(SpanKind spanKind); + + /// + /// Set the on the span. + /// + /// context to set on span. + /// This span builder for chaining. + ISpanBuilder AddLink(SpanContext spanContext); /// - /// Starts the span and set it as a current on the current context. + /// Set the on the span. /// - /// Scoped event to control the scope of span in the context. - /// Dispose to stop the span and disassiciate it from the current context. - IScope StartScopedSpan(); + /// to set on span. + /// This span builder for chaining. + ISpanBuilder AddLink(ILink link); + + /// + /// Set the on the span. + /// + /// context. + /// The attributes of the . + /// This span builder for chaining. + ISpanBuilder AddLink(SpanContext context, IDictionary attributes); /// - /// Starts the span and set it as a current on the current context, setting the out param to current span. + /// Set the record events value. /// - /// Current span. - /// Scoped event to control the scope of span in the context. - /// Dispose to stop the span and disassiciate it from the current context. - IScope StartScopedSpan(out ISpan currentSpan); + /// Value indicating whether to record span. + /// This span builder for chaining. + ISpanBuilder SetRecordEvents(bool recordEvents); + + /// + /// Starts the span. + /// + /// Span that was just started. + ISpan StartSpan(); } } diff --git a/src/OpenTelemetry.Abstractions/Trace/ITracer.cs b/src/OpenTelemetry.Abstractions/Trace/ITracer.cs index 8307ca1a082..164e3ae0519 100644 --- a/src/OpenTelemetry.Abstractions/Trace/ITracer.cs +++ b/src/OpenTelemetry.Abstractions/Trace/ITracer.cs @@ -50,27 +50,8 @@ public interface ITracer /// Gets the span builder for the span with the given name. /// /// Span name. - /// Span kind. /// Span builder for the span with the given name. - ISpanBuilder SpanBuilder(string spanName, SpanKind spanKind = SpanKind.Internal); - - /// - /// Gets the span builder for the span with the given name and parent. - /// - /// Span name. - /// Span kind. - /// Parent of the span. - /// Span builder for the span with the given name and specified parent. - ISpanBuilder SpanBuilderWithParent(string name, SpanKind kind = SpanKind.Internal, ISpan parent = null); - - /// - /// Gets the span builder for the span with the give name and remote parent context. - /// - /// Span name. - /// Span kind. - /// Remote parent context extracted from the wire. - /// Span builder for the span with the given name and specified parent span context. - ISpanBuilder SpanBuilderWithParentContext(string name, SpanKind kind = SpanKind.Internal, SpanContext parentContext = null); + ISpanBuilder SpanBuilder(string spanName); /// /// Records . This API allows to send a pre-populated span object to the diff --git a/src/OpenTelemetry/Internal/NoopScope.cs b/src/OpenTelemetry.Abstractions/Trace/NoopScope.cs similarity index 77% rename from src/OpenTelemetry/Internal/NoopScope.cs rename to src/OpenTelemetry.Abstractions/Trace/NoopScope.cs index 15111e357fc..bcb009ded6a 100644 --- a/src/OpenTelemetry/Internal/NoopScope.cs +++ b/src/OpenTelemetry.Abstractions/Trace/NoopScope.cs @@ -14,26 +14,25 @@ // limitations under the License. // -namespace OpenTelemetry.Internal +namespace OpenTelemetry.Trace { using OpenTelemetry.Context; + /// + /// No-op scope. + /// public sealed class NoopScope : IScope { - public static readonly IScope NoopInstance = new NoopScope(); + /// + /// Gets Instance of the noop scope. + /// + public static IScope Instance = new NoopScope(); private NoopScope() { } - public static IScope Instance - { - get - { - return NoopInstance; - } - } - + /// public void Dispose() { } diff --git a/src/OpenTelemetry.Abstractions/Trace/NoopSpanBuilder.cs b/src/OpenTelemetry.Abstractions/Trace/NoopSpanBuilder.cs new file mode 100644 index 00000000000..97b484c1300 --- /dev/null +++ b/src/OpenTelemetry.Abstractions/Trace/NoopSpanBuilder.cs @@ -0,0 +1,130 @@ +// +// Copyright 2018, OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +namespace OpenTelemetry.Trace +{ + using System; + using System.Collections.Generic; + + /// + /// No-op span builder. + /// + public class NoopSpanBuilder : ISpanBuilder + { + internal NoopSpanBuilder(string name) + { + if (name == null) + { + throw new ArgumentNullException(nameof(name)); + } + } + + /// + public ISpanBuilder SetRecordEvents(bool recordEvents) + { + return this; + } + + /// + public ISpan StartSpan() + { + return BlankSpan.Instance; + } + + /// + public ISpanBuilder SetSampler(ISampler sampler) + { + if (sampler == null) + { + throw new ArgumentNullException(nameof(sampler)); + } + + return this; + } + + /// + public ISpanBuilder SetParent(ISpan parent) + { + if (parent == null) + { + throw new ArgumentNullException(nameof(parent)); + } + + return this; + } + + /// + public ISpanBuilder SetParent(SpanContext remoteParent) + { + if (remoteParent == null) + { + throw new ArgumentNullException(nameof(remoteParent)); + } + + return this; + } + + /// + public ISpanBuilder SetNoParent() + { + return this; + } + + /// + public ISpanBuilder SetSpanKind(SpanKind spanKind) + { + return this; + } + + /// + public ISpanBuilder AddLink(SpanContext spanContext) + { + if (spanContext == null) + { + throw new ArgumentNullException(nameof(spanContext)); + } + + return this; + } + + /// + public ISpanBuilder AddLink(ILink link) + { + if (link == null) + { + throw new ArgumentNullException(nameof(link)); + } + + return this; + } + + /// + public ISpanBuilder AddLink(SpanContext context, IDictionary attributes) + { + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + + if (attributes == null) + { + throw new ArgumentNullException(nameof(attributes)); + } + + return this; + } + } +} diff --git a/src/OpenTelemetry/Trace/NoopTracer.cs b/src/OpenTelemetry.Abstractions/Trace/NoopTracer.cs similarity index 53% rename from src/OpenTelemetry/Trace/NoopTracer.cs rename to src/OpenTelemetry.Abstractions/Trace/NoopTracer.cs index 4f923d00554..2bd46c53b54 100644 --- a/src/OpenTelemetry/Trace/NoopTracer.cs +++ b/src/OpenTelemetry.Abstractions/Trace/NoopTracer.cs @@ -16,53 +16,52 @@ namespace OpenTelemetry.Trace { + using System; + using OpenTelemetry.Context; using OpenTelemetry.Context.Propagation; /// /// No-op tracer. /// - public sealed class NoopTracer : TracerBase, ITracer + public sealed class NoopTracer : ITracer { - private static readonly IBinaryFormat BinaryFormatValue = new BinaryFormat(); - private static readonly ITextFormat TextFormatValue = new TraceContextFormat(); + /// + /// Instance of the noop tracer. + /// + public static readonly NoopTracer Instance = new NoopTracer(); internal NoopTracer() { } /// - public override IBinaryFormat BinaryFormat - { - get - { - return BinaryFormatValue; - } - } + public ISpan CurrentSpan => BlankSpan.Instance; /// - public override ITextFormat TextFormat - { - get - { - return TextFormatValue; - } - } + public IBinaryFormat BinaryFormat => new BinaryFormat(); + + /// + public ITextFormat TextFormat => new TraceContextFormat(); /// - public override ISpanBuilder SpanBuilderWithParent(string name, SpanKind kind = SpanKind.Internal, ISpan parent = null) + public IScope WithSpan(ISpan span) { - return NoopSpanBuilder.SetParent(name, kind, parent); + return NoopScope.Instance; } /// - public override ISpanBuilder SpanBuilderWithParentContext(string name, SpanKind kind = SpanKind.Internal, SpanContext parentContext = null) + public ISpanBuilder SpanBuilder(string spanName) { - return NoopSpanBuilder.SetParent(name, kind, parentContext); + return new NoopSpanBuilder(spanName); } /// - public override void RecordSpanData(SpanData span) + public void RecordSpanData(SpanData span) { + if (span == null) + { + throw new ArgumentNullException(nameof(span)); + } } } } diff --git a/src/OpenTelemetry.Abstractions/Trace/Sampler/Internal/AlwaysSampleSampler.cs b/src/OpenTelemetry.Abstractions/Trace/Sampler/Internal/AlwaysSampleSampler.cs index e9707187067..1bf8221c7c0 100644 --- a/src/OpenTelemetry.Abstractions/Trace/Sampler/Internal/AlwaysSampleSampler.cs +++ b/src/OpenTelemetry.Abstractions/Trace/Sampler/Internal/AlwaysSampleSampler.cs @@ -24,15 +24,10 @@ internal AlwaysSampleSampler() { } - public string Description - { - get - { - return this.ToString(); - } - } + public string Description => this.ToString(); - public bool ShouldSample(SpanContext parentContext, TraceId traceId, SpanId spanId, string name, IEnumerable parentLinks) + /// + public bool ShouldSample(SpanContext parentContext, TraceId traceId, SpanId spanId, string name, IEnumerable parentLinks) { return true; } diff --git a/src/OpenTelemetry.Abstractions/Trace/Sampler/Internal/NeverSampleSampler.cs b/src/OpenTelemetry.Abstractions/Trace/Sampler/Internal/NeverSampleSampler.cs index 68540ba51a4..22b1b856b9e 100644 --- a/src/OpenTelemetry.Abstractions/Trace/Sampler/Internal/NeverSampleSampler.cs +++ b/src/OpenTelemetry.Abstractions/Trace/Sampler/Internal/NeverSampleSampler.cs @@ -18,21 +18,17 @@ namespace OpenTelemetry.Trace.Sampler.Internal { using System.Collections.Generic; + /// internal sealed class NeverSampleSampler : ISampler { internal NeverSampleSampler() { } - public string Description - { - get - { - return this.ToString(); - } - } + public string Description => this.ToString(); - public bool ShouldSample(SpanContext parentContext, TraceId traceId, SpanId spanId, string name, IEnumerable parentLinks) + /// + public bool ShouldSample(SpanContext parentContext, TraceId traceId, SpanId spanId, string name, IEnumerable links) { return false; } diff --git a/src/OpenTelemetry.Collector.AspNetCore/Implementation/HttpInListener.cs b/src/OpenTelemetry.Collector.AspNetCore/Implementation/HttpInListener.cs index 3b43f70ed04..0e7c3f0c0b5 100644 --- a/src/OpenTelemetry.Collector.AspNetCore/Implementation/HttpInListener.cs +++ b/src/OpenTelemetry.Collector.AspNetCore/Implementation/HttpInListener.cs @@ -59,13 +59,13 @@ public override void OnStartActivity(Activity activity, object payload) var path = (request.PathBase.HasValue || request.Path.HasValue) ? (request.PathBase + request.Path).ToString() : "/"; - ISpan span = null; - this.Tracer.SpanBuilderWithParentContext(path, SpanKind.Server, ctx).SetSampler(this.SamplerFactory(request)).StartScopedSpan(out span); - if (span == null) - { - // Debug.WriteLine("span is null"); - return; - } + ISpan span = this.Tracer.SpanBuilder(path) + .SetSpanKind(SpanKind.Server) + .SetParent(ctx) + .SetSampler(this.SamplerFactory(request)) + .StartSpan(); + + this.Tracer.WithSpan(span); // Note, route is missing at this stage. It will be available later diff --git a/src/OpenTelemetry.Collector.Dependencies/Implementation/HttpHandlerDiagnosticListener.cs b/src/OpenTelemetry.Collector.Dependencies/Implementation/HttpHandlerDiagnosticListener.cs index dafcb50db36..aef890c8bcd 100644 --- a/src/OpenTelemetry.Collector.Dependencies/Implementation/HttpHandlerDiagnosticListener.cs +++ b/src/OpenTelemetry.Collector.Dependencies/Implementation/HttpHandlerDiagnosticListener.cs @@ -45,7 +45,12 @@ public override void OnStartActivity(Activity activity, object payload) return; } - this.Tracer.SpanBuilder(request.RequestUri.AbsolutePath, SpanKind.Client).SetSampler(this.SamplerFactory(request)).StartScopedSpan(out var span); + var span = this.Tracer.SpanBuilder(request.RequestUri.AbsolutePath) + .SetSpanKind(SpanKind.Client) + .SetSampler(this.SamplerFactory(request)) + .StartSpan(); + this.Tracer.WithSpan(span); + span.PutHttpMethodAttribute(request.Method.ToString()); span.PutHttpHostAttribute(request.RequestUri.Host, request.RequestUri.Port); span.PutHttpPathAttribute(request.RequestUri.AbsolutePath); diff --git a/src/OpenTelemetry/Tags/NoopTagContextBuilder.cs b/src/OpenTelemetry/Tags/NoopTagContextBuilder.cs index 0d3267584c1..8097eb90737 100644 --- a/src/OpenTelemetry/Tags/NoopTagContextBuilder.cs +++ b/src/OpenTelemetry/Tags/NoopTagContextBuilder.cs @@ -18,7 +18,7 @@ namespace OpenTelemetry.Tags { using System; using OpenTelemetry.Context; - using OpenTelemetry.Internal; + using OpenTelemetry.Trace; internal sealed class NoopTagContextBuilder : TagContextBuilderBase { diff --git a/src/OpenTelemetry/Tags/NoopTagger.cs b/src/OpenTelemetry/Tags/NoopTagger.cs index 6312b82c47a..44b340e999e 100644 --- a/src/OpenTelemetry/Tags/NoopTagger.cs +++ b/src/OpenTelemetry/Tags/NoopTagger.cs @@ -18,7 +18,7 @@ namespace OpenTelemetry.Tags { using System; using OpenTelemetry.Context; - using OpenTelemetry.Internal; + using OpenTelemetry.Trace; internal sealed class NoopTagger : TaggerBase { diff --git a/src/OpenTelemetry/Tags/Tagger.cs b/src/OpenTelemetry/Tags/Tagger.cs index bf1d25fe0a8..52c37def6b9 100644 --- a/src/OpenTelemetry/Tags/Tagger.cs +++ b/src/OpenTelemetry/Tags/Tagger.cs @@ -17,7 +17,7 @@ namespace OpenTelemetry.Tags { using OpenTelemetry.Context; - using OpenTelemetry.Internal; + using OpenTelemetry.Trace; public sealed class Tagger : TaggerBase { diff --git a/src/OpenTelemetry/Trace/CurrentSpanUtils.cs b/src/OpenTelemetry/Trace/CurrentSpanUtils.cs index 4f93356484d..7bfcae89b0c 100644 --- a/src/OpenTelemetry/Trace/CurrentSpanUtils.cs +++ b/src/OpenTelemetry/Trace/CurrentSpanUtils.cs @@ -18,18 +18,13 @@ namespace OpenTelemetry.Trace { using System.Threading; using OpenTelemetry.Context; + using OpenTelemetry.Trace.Internal; internal static class CurrentSpanUtils { private static readonly AsyncLocal AsyncLocalContext = new AsyncLocal(); - public static ISpan CurrentSpan - { - get - { - return AsyncLocalContext.Value; - } - } + public static ISpan CurrentSpan => AsyncLocalContext.Value; public static IScope WithSpan(ISpan span, bool endSpan) { diff --git a/src/OpenTelemetry/Trace/Export/SpanStore/InProcessRunningSpanStore.cs b/src/OpenTelemetry/Trace/Export/SpanStore/InProcessRunningSpanStore.cs index 4b0f69e2ba0..fa7be4f662c 100644 --- a/src/OpenTelemetry/Trace/Export/SpanStore/InProcessRunningSpanStore.cs +++ b/src/OpenTelemetry/Trace/Export/SpanStore/InProcessRunningSpanStore.cs @@ -22,14 +22,14 @@ namespace OpenTelemetry.Trace.Export /// public sealed class InProcessRunningSpanStore : RunningSpanStoreBase { - private readonly ConcurrentIntrusiveList runningSpans; + private readonly ConcurrentIntrusiveList runningSpans; /// /// Constructs a new . /// public InProcessRunningSpanStore() { - this.runningSpans = new ConcurrentIntrusiveList(); + this.runningSpans = new ConcurrentIntrusiveList(); } /// @@ -37,7 +37,7 @@ public override IRunningSpanStoreSummary Summary { get { - IEnumerable allRunningSpans = this.runningSpans.Copy(); + IEnumerable allRunningSpans = this.runningSpans.Copy(); var numSpansPerName = new Dictionary(); foreach (var span in allRunningSpans) { @@ -61,7 +61,7 @@ public override IRunningSpanStoreSummary Summary /// public override IEnumerable GetRunningSpans(IRunningSpanStoreFilter filter) { - IReadOnlyCollection allRunningSpans = this.runningSpans.Copy(); + IReadOnlyCollection allRunningSpans = this.runningSpans.Copy(); var maxSpansToReturn = filter.MaxSpansToReturn == 0 ? allRunningSpans.Count : filter.MaxSpansToReturn; var ret = new List(maxSpansToReturn); foreach (var span in allRunningSpans) @@ -83,7 +83,7 @@ public override IEnumerable GetRunningSpans(IRunningSpanStoreFilter fi /// public override void OnEnd(ISpan span) { - if (span is SpanBase spanBase) + if (span is Span spanBase) { this.runningSpans.RemoveElement(spanBase); } @@ -92,7 +92,7 @@ public override void OnEnd(ISpan span) /// public override void OnStart(ISpan span) { - if (span is SpanBase spanBase) + if (span is Span spanBase) { this.runningSpans.AddElement(spanBase); } diff --git a/src/OpenTelemetry/Trace/Export/SpanStore/InProcessSampledSpanStore.cs b/src/OpenTelemetry/Trace/Export/SpanStore/InProcessSampledSpanStore.cs index 35e81ecb28d..9f52ed5ab79 100644 --- a/src/OpenTelemetry/Trace/Export/SpanStore/InProcessSampledSpanStore.cs +++ b/src/OpenTelemetry/Trace/Export/SpanStore/InProcessSampledSpanStore.cs @@ -79,7 +79,7 @@ public override ISet RegisteredSpanNamesForCollection /// public override void ConsiderForSampling(ISpan ispan) { - if (ispan is SpanBase span) + if (ispan is Span span) { lock (this.samples) { @@ -102,7 +102,7 @@ public override void ConsiderForSampling(ISpan ispan) public override IEnumerable GetErrorSampledSpans(ISampledSpanStoreErrorFilter filter) { var numSpansToReturn = filter.MaxSpansToReturn == 0 ? MaxPerSpanNameSamples : filter.MaxSpansToReturn; - var spans = Enumerable.Empty(); + var spans = Enumerable.Empty(); // Try to not keep the lock to much, do the SpanImpl -> SpanData conversion outside the lock. lock (this.samples) @@ -127,7 +127,7 @@ public override IEnumerable GetErrorSampledSpans(ISampledSpanStoreErro public override IEnumerable GetLatencySampledSpans(ISampledSpanStoreLatencyFilter filter) { var numSpansToReturn = filter.MaxSpansToReturn == 0 ? MaxPerSpanNameSamples : filter.MaxSpansToReturn; - var spans = Enumerable.Empty(); + var spans = Enumerable.Empty(); // Try to not keep the lock to much, do the SpanImpl -> SpanData conversion outside the lock. lock (this.samples) @@ -187,19 +187,19 @@ internal void InternaltRegisterSpanNamesForCollection(ICollection spanNa private sealed class Bucket { - private readonly EvictingQueue sampledSpansQueue; - private readonly EvictingQueue notSampledSpansQueue; + private readonly EvictingQueue sampledSpansQueue; + private readonly EvictingQueue notSampledSpansQueue; private DateTimeOffset lastSampledTime; private DateTimeOffset lastNotSampledTime; public Bucket(int numSamples) { - this.sampledSpansQueue = new EvictingQueue(numSamples); - this.notSampledSpansQueue = new EvictingQueue(numSamples); + this.sampledSpansQueue = new EvictingQueue(numSamples); + this.notSampledSpansQueue = new EvictingQueue(numSamples); } public static void GetSamples( - int maxSpansToReturn, ICollection output, EvictingQueue queue) + int maxSpansToReturn, ICollection output, EvictingQueue queue) { var copy = queue.ToArray(); @@ -218,8 +218,8 @@ public static void GetSamplesFilteredByLatency( TimeSpan latencyLower, TimeSpan latencyUpper, int maxSpansToReturn, - ICollection output, - EvictingQueue queue) + ICollection output, + EvictingQueue queue) { var copy = queue.ToArray(); foreach (var span in copy) @@ -237,7 +237,7 @@ public static void GetSamplesFilteredByLatency( } } - public void ConsiderForSampling(SpanBase span) + public void ConsiderForSampling(Span span) { var spanEndTime = span.EndTime; if (span.Context.TraceOptions.IsSampled) @@ -264,14 +264,14 @@ public void ConsiderForSampling(SpanBase span) } } - public void GetSamples(int maxSpansToReturn, ICollection output) + public void GetSamples(int maxSpansToReturn, ICollection output) { GetSamples(maxSpansToReturn, output, this.sampledSpansQueue); GetSamples(maxSpansToReturn, output, this.notSampledSpansQueue); } public void GetSamplesFilteredByLatency( - TimeSpan latencyLower, TimeSpan latencyUpper, int maxSpansToReturn, ICollection output) + TimeSpan latencyLower, TimeSpan latencyUpper, int maxSpansToReturn, ICollection output) { GetSamplesFilteredByLatency( latencyLower, latencyUpper, maxSpansToReturn, output, this.sampledSpansQueue); @@ -327,7 +327,7 @@ public Bucket GetErrorBucket(CanonicalCode code) return this.errorBuckets[(int)code - 1]; } - public void ConsiderForSampling(SpanBase span) + public void ConsiderForSampling(Span span) { var status = span.Status; @@ -370,9 +370,9 @@ public IDictionary GetNumbersOfErrorSampledSpans() return errorBucketSummaries; } - public IEnumerable GetErrorSamples(CanonicalCode? code, int maxSpansToReturn) + public IEnumerable GetErrorSamples(CanonicalCode? code, int maxSpansToReturn) { - var output = new List(maxSpansToReturn); + var output = new List(maxSpansToReturn); if (code.HasValue) { this.GetErrorBucket(code.Value).GetSamples(maxSpansToReturn, output); @@ -388,9 +388,9 @@ public IEnumerable GetErrorSamples(CanonicalCode? code, int maxSpansTo return output; } - public IEnumerable GetLatencySamples(TimeSpan latencyLower, TimeSpan latencyUpper, int maxSpansToReturn) + public IEnumerable GetLatencySamples(TimeSpan latencyLower, TimeSpan latencyUpper, int maxSpansToReturn) { - var output = new List(maxSpansToReturn); + var output = new List(maxSpansToReturn); for (var i = 0; i < NumLatencyBuckets; i++) { var boundaries = LatencyBucketBoundaries.Values[i]; diff --git a/src/OpenTelemetry/Trace/Internal/BlankSpan.cs b/src/OpenTelemetry/Trace/Internal/BlankSpan.cs deleted file mode 100644 index ece384d9e74..00000000000 --- a/src/OpenTelemetry/Trace/Internal/BlankSpan.cs +++ /dev/null @@ -1,117 +0,0 @@ -// -// Copyright 2018, OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -namespace OpenTelemetry.Trace.Internal -{ - using System; - using System.Collections.Generic; - - internal sealed class BlankSpan : SpanBase - { - public static readonly BlankSpan Instance = new BlankSpan(); - - private BlankSpan() - : base(SpanContext.Blank, default(SpanOptions)) - { - } - - public override string Name { get; protected set; } - - public override Status Status { get; set; } - - public override DateTimeOffset EndTime - { - get - { - return DateTimeOffset.MinValue; - } - } - - public override TimeSpan Latency - { - get - { - return TimeSpan.Zero; - } - } - - public override bool IsSampleToLocalSpanStore - { - get - { - return false; - } - } - - public override SpanId ParentSpanId - { - get - { - return null; - } - } - - public override bool HasEnded => true; - - public override bool IsRecordingEvents => false; - - public override void SetAttribute(string key, IAttributeValue value) - { - } - - public override void AddEvent(string name, IDictionary attributes) - { - } - - public override void AddEvent(IEvent addEvent) - { - } - - public override void AddLink(ILink link) - { - } - - public override void End(EndSpanOptions options) - { - } - - public override string ToString() - { - return "BlankSpan"; - } - - public override SpanData ToSpanData() - { - return null; - } - - public override void SetAttribute(string key, string value) - { - } - - public override void SetAttribute(string key, long value) - { - } - - public override void SetAttribute(string key, double value) - { - } - - public override void SetAttribute(string key, bool value) - { - } - } -} diff --git a/src/OpenTelemetry/Trace/NoopSpanBuilder.cs b/src/OpenTelemetry/Trace/NoopSpanBuilder.cs deleted file mode 100644 index e8d4f583962..00000000000 --- a/src/OpenTelemetry/Trace/NoopSpanBuilder.cs +++ /dev/null @@ -1,63 +0,0 @@ -// -// Copyright 2018, OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -namespace OpenTelemetry.Trace -{ - using System; - using System.Collections.Generic; - using OpenTelemetry.Trace.Internal; - - public class NoopSpanBuilder : SpanBuilderBase - { - private NoopSpanBuilder(string name, SpanKind kind) : base(kind) - { - if (name == null) - { - throw new ArgumentNullException(nameof(name)); - } - } - - public override ISpan StartSpan() - { - return BlankSpan.Instance; - } - - public override ISpanBuilder SetSampler(ISampler sampler) - { - return this; - } - - public override ISpanBuilder SetParentLinks(IEnumerable parentLinks) - { - return this; - } - - public override ISpanBuilder SetRecordEvents(bool recordEvents) - { - return this; - } - - internal static ISpanBuilder SetParent(string name, SpanKind kind, ISpan parent = null) - { - return new NoopSpanBuilder(name, kind); - } - - internal static ISpanBuilder SetParent(string name, SpanKind kind, SpanContext parentContext = null) - { - return new NoopSpanBuilder(name, kind); - } - } -} diff --git a/src/OpenTelemetry/Trace/Sampler/ProbabilitySampler.cs b/src/OpenTelemetry/Trace/Sampler/ProbabilitySampler.cs index e6c61af624c..60e99c7903e 100644 --- a/src/OpenTelemetry/Trace/Sampler/ProbabilitySampler.cs +++ b/src/OpenTelemetry/Trace/Sampler/ProbabilitySampler.cs @@ -20,6 +20,7 @@ namespace OpenTelemetry.Trace.Sampler using System.Collections.Generic; using OpenTelemetry.Utils; + /// public sealed class ProbabilitySampler : ISampler { private ProbabilitySampler(double probability, long idUpperBound) @@ -28,13 +29,8 @@ private ProbabilitySampler(double probability, long idUpperBound) this.IdUpperBound = idUpperBound; } - public string Description - { - get - { - return string.Format("ProbabilitySampler({0:F6})", this.Probability); - } - } + /// + public string Description => $"ProbabilitySampler({this.Probability:F6})"; public double Probability { get; } @@ -69,7 +65,8 @@ public static ProbabilitySampler Create(double probability) return new ProbabilitySampler(probability, idUpperBound); } - public bool ShouldSample(SpanContext parentContext, TraceId traceId, SpanId spanId, string name, IEnumerable parentLinks) + /// + public bool ShouldSample(SpanContext parentContext, TraceId traceId, SpanId spanId, string name, IEnumerable links) { // If the parent is sampled keep the sampling decision. if (parentContext != null && parentContext.TraceOptions.IsSampled) @@ -77,10 +74,10 @@ public bool ShouldSample(SpanContext parentContext, TraceId traceId, SpanId span return true; } - if (parentLinks != null) + if (links != null) { // If any parent link is sampled keep the sampling decision. - foreach (var parentLink in parentLinks) + foreach (var parentLink in links) { if (parentLink.Context.TraceOptions.IsSampled) { diff --git a/src/OpenTelemetry/Trace/Span.cs b/src/OpenTelemetry/Trace/Span.cs index 09e913e3824..e68a8fc0a5d 100644 --- a/src/OpenTelemetry/Trace/Span.cs +++ b/src/OpenTelemetry/Trace/Span.cs @@ -25,8 +25,10 @@ namespace OpenTelemetry.Trace using OpenTelemetry.Trace.Export; using OpenTelemetry.Utils; - /// - public sealed class Span : SpanBase + /// + /// Span implementation. + /// + public sealed class Span : ISpan, IElement { private readonly SpanId parentSpanId; private readonly ITraceParams traceParams; @@ -50,8 +52,9 @@ private Span( ITraceParams traceParams, IStartEndHandler startEndHandler, Timer timestampConverter) - : base(context, options) { + this.Context = context; + this.Options = options; this.parentSpanId = parentSpanId; this.Name = name; this.traceParams = traceParams ?? throw new ArgumentNullException(nameof(traceParams)); @@ -79,11 +82,20 @@ private Span( } } + public SpanContext Context { get; } + + public SpanOptions Options { get; } + + public string Name { get; private set; } + /// - public override string Name { get; protected set; } + public Span Next { get; set; } + + /// + public Span Previous { get; set; } /// - public override Status Status + public Status Status { get { @@ -108,13 +120,12 @@ public override Status Status return; } - this.status = value; + this.status = value ?? throw new ArgumentNullException(nameof(value)); } } } - /// - public override DateTimeOffset EndTime + public DateTimeOffset EndTime { get { @@ -125,8 +136,7 @@ public override DateTimeOffset EndTime } } - /// - public override TimeSpan Latency + public TimeSpan Latency { get { @@ -137,8 +147,7 @@ public override TimeSpan Latency } } - /// - public override bool IsSampleToLocalSpanStore + public bool IsSampleToLocalSpanStore { get { @@ -152,22 +161,22 @@ public override bool IsSampleToLocalSpanStore return this.sampleToLocalSpanStore; } } + + set + { + lock (this.@lock) + { + this.sampleToLocalSpanStore = value; + } + } } - /// - public override SpanId ParentSpanId => this.parentSpanId; + public SpanId ParentSpanId => this.parentSpanId; - /// - public override bool HasEnded => this.hasBeenEnded; + public bool HasEnded => this.hasBeenEnded; /// - public override bool IsRecordingEvents - { - get - { - return this.Options.HasFlag(SpanOptions.RecordEvents); - } - } + public bool IsRecordingEvents => this.Options.HasFlag(SpanOptions.RecordEvents); /// /// Gets or sets span kind. @@ -218,9 +227,25 @@ private TraceEvents InitializedLinks private Status StatusWithDefault => this.status ?? Trace.Status.Ok; + /// + public void UpdateName(string name) + { + this.Name = name ?? throw new ArgumentNullException(nameof(name)); + } + /// - public override void SetAttribute(string key, IAttributeValue value) + public void SetAttribute(string key, IAttributeValue value) { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + if (!this.IsRecordingEvents) { return; @@ -239,8 +264,43 @@ public override void SetAttribute(string key, IAttributeValue value) } /// - public override void AddEvent(string name, IDictionary attributes) + public void AddEvent(string name) + { + if (name == null) + { + throw new ArgumentNullException(nameof(name)); + } + + if (!this.IsRecordingEvents) + { + return; + } + + lock (this.@lock) + { + if (this.hasBeenEnded) + { + // logger.log(Level.FINE, "Calling AddEvent() on an ended Span."); + return; + } + + this.InitializedEvents.AddEvent(new EventWithTime(this.TimestampConverter.Now, Event.Create(name))); + } + } + + /// + public void AddEvent(string name, IDictionary eventAttributes) { + if (name == null) + { + throw new ArgumentNullException(nameof(name)); + } + + if (eventAttributes == null) + { + throw new ArgumentNullException(nameof(eventAttributes)); + } + if (!this.IsRecordingEvents) { return; @@ -254,13 +314,18 @@ public override void AddEvent(string name, IDictionary return; } - this.InitializedEvents.AddEvent(new EventWithTime(this.TimestampConverter.Now, Event.Create(name, attributes))); + this.InitializedEvents.AddEvent(new EventWithTime(this.TimestampConverter.Now, Event.Create(name, eventAttributes))); } } /// - public override void AddEvent(IEvent addEvent) + public void AddEvent(IEvent addEvent) { + if (addEvent == null) + { + throw new ArgumentNullException(nameof(addEvent)); + } + if (!this.IsRecordingEvents) { return; @@ -284,8 +349,13 @@ public override void AddEvent(IEvent addEvent) } /// - public override void AddLink(ILink link) + public void AddLink(ILink link) { + if (link == null) + { + throw new ArgumentNullException(nameof(link)); + } + if (!this.IsRecordingEvents) { return; @@ -309,7 +379,7 @@ public override void AddLink(ILink link) } /// - public override void End(EndSpanOptions options) + public void End() { if (!this.IsRecordingEvents) { @@ -324,12 +394,6 @@ public override void End(EndSpanOptions options) return; } - if (options.Status != null) - { - this.status = options.Status; - } - - this.sampleToLocalSpanStore = options.SampleToLocalSpanStore; this.endTime = this.TimestampConverter.Now; this.hasBeenEnded = true; } @@ -337,8 +401,7 @@ public override void End(EndSpanOptions options) this.startEndHandler.OnEnd(this); } - /// - public override SpanData ToSpanData() + public SpanData ToSpanData() { if (!this.IsRecordingEvents) { @@ -367,8 +430,18 @@ public override SpanData ToSpanData() } /// - public override void SetAttribute(string key, string value) + public void SetAttribute(string key, string value) { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + if (!this.IsRecordingEvents) { return; @@ -378,8 +451,13 @@ public override void SetAttribute(string key, string value) } /// - public override void SetAttribute(string key, long value) + public void SetAttribute(string key, long value) { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + if (!this.IsRecordingEvents) { return; @@ -389,8 +467,13 @@ public override void SetAttribute(string key, long value) } /// - public override void SetAttribute(string key, double value) + public void SetAttribute(string key, double value) { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + if (!this.IsRecordingEvents) { return; @@ -400,8 +483,13 @@ public override void SetAttribute(string key, double value) } /// - public override void SetAttribute(string key, bool value) + public void SetAttribute(string key, bool value) { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + if (!this.IsRecordingEvents) { return; diff --git a/src/OpenTelemetry/Trace/SpanBase.cs b/src/OpenTelemetry/Trace/SpanBase.cs deleted file mode 100644 index dab0f13a43b..00000000000 --- a/src/OpenTelemetry/Trace/SpanBase.cs +++ /dev/null @@ -1,164 +0,0 @@ -// -// Copyright 2018, OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -namespace OpenTelemetry.Trace -{ - using System; - using System.Collections.Generic; - using OpenTelemetry.Utils; - - /// - /// Span base class. - /// - public abstract class SpanBase : ISpan, IElement - { - private static readonly IDictionary EmptyAttributes = new Dictionary(); - - internal SpanBase() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// Span context. - /// Span creation options. - protected SpanBase(SpanContext context, SpanOptions options = SpanOptions.None) - { - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } - - if (context.TraceOptions.IsSampled && !options.HasFlag(SpanOptions.RecordEvents)) - { - throw new ArgumentOutOfRangeException("Span is sampled, but does not have RECORD_EVENTS set."); - } - - this.Context = context; - this.Options = options; - } - - /// - /// Gets or sets the span name. Use to explicitly set the span name. - /// - public abstract string Name { get; protected set; } - - /// - public virtual SpanContext Context { get; } - - /// - /// Gets the span options. - /// - public virtual SpanOptions Options { get; } - - /// - public abstract Status Status { get; set; } - - /// - public SpanBase Next { get; set; } - - /// - public SpanBase Previous { get; set; } - - /// - /// Gets the span end time. - /// - public abstract DateTimeOffset EndTime { get; } - - /// - /// Gets the latency (difference beteen stat and end time). - /// - public abstract TimeSpan Latency { get; } - - /// - /// Gets a value indicating whether span stored in local store. - /// - public abstract bool IsSampleToLocalSpanStore { get; } - - /// - /// Gets the parent span id. - /// - public abstract SpanId ParentSpanId { get; } - - /// - /// Gets a value indicating whether this span was already stopped. - /// - public abstract bool HasEnded { get; } - - /// - public abstract bool IsRecordingEvents { get; } - - /// - public void UpdateName(string name) - { - this.Name = name; - } - - /// - public abstract void SetAttribute(string key, IAttributeValue value); - - /// - public void AddEvent(string name) - { - this.AddEvent(name, EmptyAttributes); - } - - /// - public abstract void AddEvent(string name, IDictionary attributes); - - /// - public abstract void AddEvent(IEvent addEvent); - - /// - public abstract void AddLink(ILink link); - - /// - public abstract void End(EndSpanOptions options); - - /// - public void End() - { - this.End(EndSpanOptions.Default); - } - - /// - public override string ToString() - { - return "Span[" + - this.Name + - "]"; - } - - /// - /// Converts this span into span data for exporting purposes. - /// - /// Span Data corresponding current span. - public abstract SpanData ToSpanData(); - - /// - public abstract void SetAttribute(string key, string value); - - /// - public abstract void SetAttribute(string key, long value); - - /// - public abstract void SetAttribute(string key, double value); - - /// - public abstract void SetAttribute(string key, bool value); - } -} diff --git a/src/OpenTelemetry/Trace/SpanBuilder.cs b/src/OpenTelemetry/Trace/SpanBuilder.cs index 55f5d14f2c6..7b6f11eeed9 100644 --- a/src/OpenTelemetry/Trace/SpanBuilder.cs +++ b/src/OpenTelemetry/Trace/SpanBuilder.cs @@ -18,120 +18,209 @@ namespace OpenTelemetry.Trace { using System; using System.Collections.Generic; - using System.Linq; using OpenTelemetry.Internal; using OpenTelemetry.Trace.Config; /// - public class SpanBuilder : SpanBuilderBase + public class SpanBuilder : ISpanBuilder { - private SpanBuilder(string name, SpanKind kind, SpanBuilderOptions options, SpanContext parentContext = null, ISpan parent = null) : base(kind) + private readonly SpanBuilderOptions options; + private readonly string name; + + private SpanKind kind; + private ISpan parent; + private SpanContext parentSpanContext; + private ParentType parentType = ParentType.CurrentSpan; + private ISampler sampler; + private List links; + private bool recordEvents; + private Timer timestampConverter; + + internal SpanBuilder(string name, SpanBuilderOptions options) { - this.Name = name ?? throw new ArgumentNullException(nameof(name)); - this.Parent = parent; - this.ParentSpanContext = parentContext; - this.Options = options; + this.name = name ?? throw new ArgumentNullException(nameof(name)); + this.options = options; } - private SpanBuilderOptions Options { get; set; } - - private string Name { get; set; } + private enum ParentType + { + CurrentSpan, + ExplicitParent, + ExplicitRemoteParent, + NoParent, + } - private ISpan Parent { get; set; } + /// + public ISpanBuilder SetSampler(ISampler sampler) + { + this.sampler = sampler ?? throw new ArgumentNullException(nameof(sampler)); + return this; + } - private SpanContext ParentSpanContext { get; set; } + /// + public ISpanBuilder SetParent(ISpan parent) + { + this.parent = parent ?? throw new ArgumentNullException(nameof(parent)); + this.parentType = ParentType.ExplicitParent; + this.timestampConverter = ((Span)parent)?.TimestampConverter; + this.parentSpanContext = null; + return this; + } - private ISampler Sampler { get; set; } + /// + public ISpanBuilder SetParent(SpanContext remoteParent) + { + this.parentSpanContext = remoteParent ?? throw new ArgumentNullException(nameof(remoteParent)); + this.parent = null; + this.parentType = ParentType.ExplicitRemoteParent; + return this; + } - private IEnumerable ParentLinks { get; set; } = Enumerable.Empty(); + /// + public ISpanBuilder SetNoParent() + { + this.parentType = ParentType.NoParent; + this.parentSpanContext = null; + this.parentSpanContext = null; + return this; + } - private bool RecordEvents { get; set; } + /// + public ISpanBuilder SetSpanKind(SpanKind spanKind) + { + this.kind = spanKind; + return this; + } /// - public override ISpan StartSpan() + public ISpanBuilder AddLink(SpanContext spanContext) { - var parentContext = this.ParentSpanContext; - Timer timestampConverter = null; - if (this.ParentSpanContext == null) + if (spanContext == null) { - // This is not a child of a remote Span. Get the parent SpanContext from the parent Span if - // any. - var parent = this.Parent; - if (parent != null) - { - parentContext = parent.Context; - - // Pass the timestamp converter from the parent to ensure that the recorded events are in - // the right order. Implementation uses System.nanoTime() which is monotonically increasing. - if (parent is Span) - { - timestampConverter = ((Span)parent).TimestampConverter; - } - } + throw new ArgumentNullException(nameof(spanContext)); } - return this.StartSpanInternal( - parentContext, - this.Name, - this.Sampler, - this.ParentLinks, - this.RecordEvents, - timestampConverter); + return this.AddLink(Link.FromSpanContext(spanContext)); } /// - public override ISpanBuilder SetSampler(ISampler sampler) + public ISpanBuilder AddLink(SpanContext spanContext, IDictionary attributes) { - this.Sampler = sampler ?? throw new ArgumentNullException(nameof(sampler)); - return this; + if (spanContext == null) + { + throw new ArgumentNullException(nameof(spanContext)); + } + + if (attributes == null) + { + throw new ArgumentNullException(nameof(attributes)); + } + + return this.AddLink(Link.FromSpanContext(spanContext, attributes)); } /// - public override ISpanBuilder SetParentLinks(IEnumerable parentLinks) + public ISpanBuilder AddLink(ILink link) { - this.ParentLinks = parentLinks ?? throw new ArgumentNullException(nameof(parentLinks)); + if (link == null) + { + throw new ArgumentNullException(nameof(link)); + } + + if (this.links == null) + { + this.links = new List(); + } + + this.links.Add(link); + return this; } /// - public override ISpanBuilder SetRecordEvents(bool recordEvents) + public ISpanBuilder SetRecordEvents(bool recordEvents) { - this.RecordEvents = recordEvents; + this.recordEvents = recordEvents; return this; } - internal static ISpanBuilder Create(string name, SpanKind kind, ISpan parent, SpanBuilderOptions options) + /// + public ISpan StartSpan() { - return new SpanBuilder(name, kind, options, null, parent); - } + SpanContext parentContext = FindParent(this.parentType, this.parent, this.parentSpanContext); + var activeTraceParams = this.options.TraceConfig.ActiveTraceParams; + var random = this.options.RandomHandler; + TraceId traceId; + var spanId = SpanId.GenerateRandomId(random); + SpanId parentSpanId = null; + TraceOptionsBuilder traceOptionsBuilder; + if (parentContext == null || !parentContext.IsValid) + { + // New root span. + traceId = TraceId.GenerateRandomId(random); + traceOptionsBuilder = TraceOptions.Builder(); + } + else + { + // New child span. + traceId = parentContext.TraceId; + parentSpanId = parentContext.SpanId; + traceOptionsBuilder = TraceOptions.Builder(parentContext.TraceOptions); + } - internal static ISpanBuilder Create(string name, SpanKind kind, SpanContext parentContext, SpanBuilderOptions options) - { - return new SpanBuilder(name, kind, options, parentContext, null); + traceOptionsBuilder.SetIsSampled( + MakeSamplingDecision( + parentContext, + this.name, + this.sampler, + this.links, + traceId, + spanId, + activeTraceParams)); + var traceOptions = traceOptionsBuilder.Build(); + var spanOptions = SpanOptions.None; + + if (traceOptions.IsSampled || this.recordEvents) + { + spanOptions = SpanOptions.RecordEvents; + } + + var span = Span.StartSpan( + SpanContext.Create(traceId, spanId, traceOptions, parentContext?.Tracestate ?? Tracestate.Empty), + spanOptions, + this.name, + this.kind, + parentSpanId, + activeTraceParams, + this.options.StartEndHandler, + this.timestampConverter); + LinkSpans(span, this.links); + return span; } - private static bool IsAnyParentLinkSampled(IEnumerable parentLinks) + private static bool IsAnyParentLinkSampled(List parentLinks) { - foreach (var parentLink in parentLinks) + if (parentLinks != null) { - if (parentLink.Context.TraceOptions.IsSampled) + foreach (var parentLink in parentLinks) { - return true; + if (parentLink.Context.TraceOptions.IsSampled) + { + return true; + } } } return false; } - private static void LinkSpans(ISpan span, IEnumerable parentLinks) + private static void LinkSpans(ISpan span, List parentLinks) { - if (parentLinks.Any()) + if (parentLinks != null) { - var childLink = Link.FromSpanContext(span.Context); - foreach (var linkedSpan in parentLinks) + foreach (var link in parentLinks) { - linkedSpan.AddLink(childLink); - span.AddLink(Link.FromSpanContext(linkedSpan.Context)); + span.AddLink(link); } } } @@ -140,7 +229,7 @@ private static bool MakeSamplingDecision( SpanContext parent, string name, ISampler sampler, - IEnumerable parentLinks, + List parentLinks, TraceId traceId, SpanId spanId, ITraceParams activeTraceParams) @@ -164,62 +253,22 @@ private static bool MakeSamplingDecision( return parent.TraceOptions.IsSampled || IsAnyParentLinkSampled(parentLinks); } - private ISpan StartSpanInternal( - SpanContext parent, - string name, - ISampler sampler, - IEnumerable parentLinks, - bool recordEvents, - Timer timestampConverter) + private static SpanContext FindParent(ParentType parentType, ISpan explicitParent, SpanContext remoteParent) { - var activeTraceParams = this.Options.TraceConfig.ActiveTraceParams; - var random = this.Options.RandomHandler; - TraceId traceId; - var spanId = SpanId.GenerateRandomId(random); - SpanId parentSpanId = null; - TraceOptionsBuilder traceOptionsBuilder; - if (parent == null || !parent.IsValid) - { - // New root span. - traceId = TraceId.GenerateRandomId(random); - traceOptionsBuilder = TraceOptions.Builder(); - } - else + switch (parentType) { - // New child span. - traceId = parent.TraceId; - parentSpanId = parent.SpanId; - traceOptionsBuilder = TraceOptions.Builder(parent.TraceOptions); + case ParentType.NoParent: + return null; + case ParentType.CurrentSpan: + ISpan currentSpan = CurrentSpanUtils.CurrentSpan; + return currentSpan?.Context; + case ParentType.ExplicitParent: + return explicitParent?.Context; + case ParentType.ExplicitRemoteParent: + return remoteParent; + default: + throw new ArgumentException($"Unknown parentType {parentType}"); } - - traceOptionsBuilder.SetIsSampled( - MakeSamplingDecision( - parent, - name, - sampler, - parentLinks, - traceId, - spanId, - activeTraceParams)); - var traceOptions = traceOptionsBuilder.Build(); - var spanOptions = SpanOptions.None; - - if (traceOptions.IsSampled || recordEvents) - { - spanOptions = SpanOptions.RecordEvents; - } - - var span = Span.StartSpan( - SpanContext.Create(traceId, spanId, traceOptions, parent?.Tracestate ?? Tracestate.Empty), - spanOptions, - name, - this.Kind, - parentSpanId, - activeTraceParams, - this.Options.StartEndHandler, - timestampConverter); - LinkSpans(span, parentLinks); - return span; } } } diff --git a/src/OpenTelemetry/Trace/SpanBuilderBase.cs b/src/OpenTelemetry/Trace/SpanBuilderBase.cs deleted file mode 100644 index 53e6f232ed1..00000000000 --- a/src/OpenTelemetry/Trace/SpanBuilderBase.cs +++ /dev/null @@ -1,54 +0,0 @@ -// -// Copyright 2018, OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -namespace OpenTelemetry.Trace -{ - using System.Collections.Generic; - using OpenTelemetry.Context; - - public abstract class SpanBuilderBase : ISpanBuilder - { - protected SpanBuilderBase(SpanKind kind) - { - this.Kind = kind; - } - - private SpanBuilderBase() - { - } - - protected SpanKind Kind { get; private set; } - - public abstract ISpanBuilder SetSampler(ISampler sampler); - - public abstract ISpanBuilder SetParentLinks(IEnumerable parentLinks); - - public abstract ISpanBuilder SetRecordEvents(bool recordEvents); - - public abstract ISpan StartSpan(); - - public IScope StartScopedSpan() - { - return CurrentSpanUtils.WithSpan(this.StartSpan(), true); - } - - public IScope StartScopedSpan(out ISpan currentSpan) - { - currentSpan = this.StartSpan(); - return CurrentSpanUtils.WithSpan(currentSpan, true); - } - } -} diff --git a/src/OpenTelemetry/Trace/Tracer.cs b/src/OpenTelemetry/Trace/Tracer.cs index f8941aa9dd2..b44c8d9aa36 100644 --- a/src/OpenTelemetry/Trace/Tracer.cs +++ b/src/OpenTelemetry/Trace/Tracer.cs @@ -16,18 +16,19 @@ namespace OpenTelemetry.Trace { + using System; using System.Threading; + using OpenTelemetry.Context; using OpenTelemetry.Context.Propagation; using OpenTelemetry.Trace.Config; using OpenTelemetry.Trace.Export; + using OpenTelemetry.Trace.Internal; /// - public sealed class Tracer : TracerBase + public sealed class Tracer : ITracer { private readonly SpanBuilderOptions spanBuilderOptions; private readonly IExportComponent exportComponent; - private readonly IBinaryFormat binaryFormat; - private readonly ITextFormat textFormat; public Tracer(IRandomGenerator randomGenerator, IStartEndHandler startEndHandler, ITraceConfig traceConfig, IExportComponent exportComponent) : this(randomGenerator, startEndHandler, traceConfig, exportComponent, null, null) @@ -37,33 +38,41 @@ public Tracer(IRandomGenerator randomGenerator, IStartEndHandler startEndHandler public Tracer(IRandomGenerator randomGenerator, IStartEndHandler startEndHandler, ITraceConfig traceConfig, IExportComponent exportComponent, IBinaryFormat binaryFormat, ITextFormat textFormat) { this.spanBuilderOptions = new SpanBuilderOptions(randomGenerator, startEndHandler, traceConfig); - this.binaryFormat = binaryFormat ?? new BinaryFormat(); - this.textFormat = textFormat ?? new TraceContextFormat(); + this.BinaryFormat = binaryFormat ?? new BinaryFormat(); + this.TextFormat = textFormat ?? new TraceContextFormat(); this.exportComponent = exportComponent; } /// - public override IBinaryFormat BinaryFormat => this.binaryFormat; + public ISpan CurrentSpan => CurrentSpanUtils.CurrentSpan ?? BlankSpan.Instance; /// - public override ITextFormat TextFormat => this.textFormat; + public IBinaryFormat BinaryFormat { get; } /// - public override void RecordSpanData(SpanData span) + public ITextFormat TextFormat { get; } + + /// + public IScope WithSpan(ISpan span) { - this.exportComponent.SpanExporter.ExportAsync(span, CancellationToken.None); + if (span == null) + { + throw new ArgumentNullException(nameof(span)); + } + + return CurrentSpanUtils.WithSpan(span, true); } /// - public override ISpanBuilder SpanBuilderWithParent(string name, SpanKind kind = SpanKind.Internal, ISpan parent = null) + public ISpanBuilder SpanBuilder(string spanName) { - return Trace.SpanBuilder.Create(name, kind, parent, this.spanBuilderOptions); + return new SpanBuilder(spanName, this.spanBuilderOptions); } /// - public override ISpanBuilder SpanBuilderWithParentContext(string name, SpanKind kind = SpanKind.Internal, SpanContext parentContext = null) + public void RecordSpanData(SpanData span) { - return Trace.SpanBuilder.Create(name, kind, parentContext, this.spanBuilderOptions); + this.exportComponent.SpanExporter.ExportAsync(span, CancellationToken.None); } } } diff --git a/src/OpenTelemetry/Trace/TracerBase.cs b/src/OpenTelemetry/Trace/TracerBase.cs deleted file mode 100644 index e2869554d59..00000000000 --- a/src/OpenTelemetry/Trace/TracerBase.cs +++ /dev/null @@ -1,82 +0,0 @@ -// -// Copyright 2018, OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -namespace OpenTelemetry.Trace -{ - using System; - using OpenTelemetry.Context; - using OpenTelemetry.Context.Propagation; - using OpenTelemetry.Trace.Internal; - - /// - public abstract class TracerBase : ITracer - { - private static readonly NoopTracer NoopTracerInstance = new NoopTracer(); - - /// - public ISpan CurrentSpan - { - get - { - var currentSpan = CurrentSpanUtils.CurrentSpan; - return currentSpan ?? BlankSpan.Instance; - } - } - - /// - public abstract IBinaryFormat BinaryFormat { get; } - - /// - public abstract ITextFormat TextFormat { get; } - - /// - /// Gets no-op tracer. - /// - internal static NoopTracer NoopTracer - { - get - { - return NoopTracerInstance; - } - } - - /// - public IScope WithSpan(ISpan span) - { - if (span == null) - { - throw new ArgumentNullException(nameof(span)); - } - - return CurrentSpanUtils.WithSpan(span, false); - } - - /// - public ISpanBuilder SpanBuilder(string spanName, SpanKind spanKind = SpanKind.Internal) - { - return this.SpanBuilderWithParent(spanName, spanKind, CurrentSpanUtils.CurrentSpan); - } - - /// - public abstract ISpanBuilder SpanBuilderWithParent(string spanName, SpanKind spanKind = SpanKind.Internal, ISpan parent = null); - - /// - public abstract ISpanBuilder SpanBuilderWithParentContext(string spanName, SpanKind spanKind = SpanKind.Internal, SpanContext remoteParentSpanContext = null); - - /// - public abstract void RecordSpanData(SpanData span); - } -} diff --git a/test/OpenTelemetry.Collector.StackExchangeRedis.Tests/Implementation/RedisProfilerEntryToSpanConverterSamplingTests.cs b/test/OpenTelemetry.Collector.StackExchangeRedis.Tests/Implementation/RedisProfilerEntryToSpanConverterSamplingTests.cs index 7b2129c064c..3593e9ec80b 100644 --- a/test/OpenTelemetry.Collector.StackExchangeRedis.Tests/Implementation/RedisProfilerEntryToSpanConverterSamplingTests.cs +++ b/test/OpenTelemetry.Collector.StackExchangeRedis.Tests/Implementation/RedisProfilerEntryToSpanConverterSamplingTests.cs @@ -33,7 +33,7 @@ public void ShouldSampleRespectsSamplerChoice() It.IsAny(), It.IsAny(), It.IsAny(), - It.IsAny>())).Returns(true); + It.IsAny>())).Returns(true); Assert.True(RedisProfilerEntryToSpanConverter.ShouldSample(SpanContext.Blank, "SET", m.Object, out var context, out var parentId)); @@ -43,7 +43,7 @@ public void ShouldSampleRespectsSamplerChoice() It.IsAny(), It.IsAny(), It.IsAny(), - It.IsAny>())).Returns(false); + It.IsAny>())).Returns(false); Assert.False(RedisProfilerEntryToSpanConverter.ShouldSample(SpanContext.Blank, "SET", m.Object, out context, out parentId)); } @@ -68,7 +68,7 @@ public void ShouldSamplePassesArgumentsToSamplerAndReturnsInContext() It.Is(y => y == traceId && y == context.TraceId), It.Is(y => y.IsValid && y == context.SpanId), It.Is(y => y == "SET"), - It.Is>(y => y == null))); + It.Is>(y => y == null))); } [Fact] @@ -80,7 +80,7 @@ public void ShouldSampleGeneratesNewTraceIdForInvalidContext() It.IsAny(), It.IsAny(), It.IsAny(), - It.IsAny>())).Returns((SpanContext parentContext, TraceId traceId, SpanId spanId, string name, IEnumerable parentLinks) => parentContext.TraceOptions.IsSampled); + It.IsAny>())).Returns((SpanContext parentContext, TraceId traceId, SpanId spanId, string name, IEnumerable parentLinks) => parentContext.TraceOptions.IsSampled); RedisProfilerEntryToSpanConverter.ShouldSample(SpanContext.Blank, "SET", m.Object, out var context, out var parentId); @@ -89,7 +89,7 @@ public void ShouldSampleGeneratesNewTraceIdForInvalidContext() It.Is(y => y.IsValid && y == context.TraceId), It.Is(y => y.IsValid && y == context.SpanId), It.Is(y => y == "SET"), - It.Is>(y => y == null))); + It.Is>(y => y == null))); Assert.Equal(TraceOptions.Default, context.TraceOptions); } diff --git a/test/OpenTelemetry.Collector.StackExchangeRedis.Tests/Implementation/RedisProfilerEntryToSpanConverterTests.cs b/test/OpenTelemetry.Collector.StackExchangeRedis.Tests/Implementation/RedisProfilerEntryToSpanConverterTests.cs index 69d37394869..4cc7cade42f 100644 --- a/test/OpenTelemetry.Collector.StackExchangeRedis.Tests/Implementation/RedisProfilerEntryToSpanConverterTests.cs +++ b/test/OpenTelemetry.Collector.StackExchangeRedis.Tests/Implementation/RedisProfilerEntryToSpanConverterTests.cs @@ -33,7 +33,7 @@ public void DrainSessionUsesCommandAsName() var parentSpan = BlankSpan.Instance; var profiledCommand = new Mock(); var sampler = new Mock(); - sampler.Setup(x => x.ShouldSample(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>())).Returns(true); + sampler.Setup(x => x.ShouldSample(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>())).Returns(true); profiledCommand.Setup(m => m.Command).Returns("SET"); var result = new List(); RedisProfilerEntryToSpanConverter.DrainSession(parentSpan, new IProfiledCommand[] { profiledCommand.Object }, sampler.Object, result); diff --git a/test/OpenTelemetry.Tests/Impl/Tags/NoopTagsTest.cs b/test/OpenTelemetry.Tests/Impl/Tags/NoopTagsTest.cs index 98bfb427370..ccd3391fdd6 100644 --- a/test/OpenTelemetry.Tests/Impl/Tags/NoopTagsTest.cs +++ b/test/OpenTelemetry.Tests/Impl/Tags/NoopTagsTest.cs @@ -14,6 +14,8 @@ // limitations under the License. // +using OpenTelemetry.Trace; + namespace OpenTelemetry.Tags.Test { using System; diff --git a/test/OpenTelemetry.Tests/Impl/Trace/BlankSpanTest.cs b/test/OpenTelemetry.Tests/Impl/Trace/BlankSpanTest.cs index 1ad2e214262..8c55220bb99 100644 --- a/test/OpenTelemetry.Tests/Impl/Trace/BlankSpanTest.cs +++ b/test/OpenTelemetry.Tests/Impl/Trace/BlankSpanTest.cs @@ -14,21 +14,15 @@ // limitations under the License. // +using System; + namespace OpenTelemetry.Trace.Test { using System.Collections.Generic; - using OpenTelemetry.Trace.Internal; using Xunit; public class BlankSpanTest { - [Fact] - public void HasInvalidContextAndDefaultSpanOptions() - { - Assert.Equal(SpanContext.Blank, BlankSpan.Instance.Context); - Assert.True(BlankSpan.Instance.Options.HasFlag(SpanOptions.None)); - } - [Fact] public void DoNotCrash() { @@ -60,9 +54,28 @@ public void DoNotCrash() BlankSpan.Instance.AddEvent(Event.Create("MyEvent")); BlankSpan.Instance.AddLink( Link.FromSpanContext(SpanContext.Blank)); + + Assert.False(BlankSpan.Instance.Context.IsValid); + Assert.False(BlankSpan.Instance.IsRecordingEvents); + Assert.Equal(Status.Ok, BlankSpan.Instance.Status); BlankSpan.Instance.Status = Status.Ok; - BlankSpan.Instance.End(EndSpanOptions.Default); BlankSpan.Instance.End(); } + + [Fact] + public void BadArguments() + { + Assert.Throws(() => BlankSpan.Instance.Status = null); + Assert.Throws(() => BlankSpan.Instance.UpdateName(null)); + Assert.Throws(() => BlankSpan.Instance.SetAttribute(null, string.Empty)); + Assert.Throws(() => BlankSpan.Instance.SetAttribute(string.Empty, (IAttributeValue)null)); + Assert.Throws(() => BlankSpan.Instance.SetAttribute(null, AttributeValue.StringAttributeValue("foo"))); + Assert.Throws(() => BlankSpan.Instance.SetAttribute(null, 1L)); + Assert.Throws(() => BlankSpan.Instance.SetAttribute(null, 0.1d)); + Assert.Throws(() => BlankSpan.Instance.SetAttribute(null, true)); + Assert.Throws(() => BlankSpan.Instance.AddEvent((string)null)); + Assert.Throws(() => BlankSpan.Instance.AddEvent((IEvent)null)); + Assert.Throws(() => BlankSpan.Instance.AddLink(null)); + } } } diff --git a/test/OpenTelemetry.Tests/Impl/Trace/CurrentSpanUtilsTest.cs b/test/OpenTelemetry.Tests/Impl/Trace/CurrentSpanUtilsTest.cs index 5c813d327f7..e6163921fd0 100644 --- a/test/OpenTelemetry.Tests/Impl/Trace/CurrentSpanUtilsTest.cs +++ b/test/OpenTelemetry.Tests/Impl/Trace/CurrentSpanUtilsTest.cs @@ -38,7 +38,7 @@ public CurrentSpanUtilsTest() Tracestate.Empty); spanOptions = SpanOptions.RecordEvents; - var mockSpan = new Mock(spanContext, spanOptions) { CallBase = true }; + var mockSpan = new Mock() { CallBase = true }; span = mockSpan.Object; } diff --git a/test/OpenTelemetry.Tests/Impl/Trace/Export/InProcessSampledSpanStoreTest.cs b/test/OpenTelemetry.Tests/Impl/Trace/Export/InProcessSampledSpanStoreTest.cs index a16403a51a8..a2d1c1ddf0d 100644 --- a/test/OpenTelemetry.Tests/Impl/Trace/Export/InProcessSampledSpanStoreTest.cs +++ b/test/OpenTelemetry.Tests/Impl/Trace/Export/InProcessSampledSpanStoreTest.cs @@ -107,7 +107,9 @@ public void RegisterSpanNamesViaSpanBuilderOption() Assert.Contains(REGISTERED_SPAN_NAME, sampleStore.RegisteredSpanNamesForCollection); Assert.Equal(1, sampleStore.RegisteredSpanNamesForCollection.Count); - CreateSampledSpan(NOT_REGISTERED_SPAN_NAME).End(EndSpanOptions.Builder().SetSampleToLocalSpanStore(true).Build()); + var span = CreateSampledSpan(NOT_REGISTERED_SPAN_NAME); + span.IsSampleToLocalSpanStore = true; + span.End(); Assert.Contains(REGISTERED_SPAN_NAME, sampleStore.RegisteredSpanNamesForCollection); Assert.Contains(NOT_REGISTERED_SPAN_NAME, sampleStore.RegisteredSpanNamesForCollection); @@ -144,7 +146,9 @@ public void GetErrorSampledSpans() { var span = CreateSampledSpan(REGISTERED_SPAN_NAME) as Span; interval += TimeSpan.FromTicks(10); - span.End(EndSpanOptions.Builder().SetStatus(Status.Cancelled).Build()); + span.Status = Status.Cancelled; + span.End(); + var samples = sampleStore.GetErrorSampledSpans( SampledSpanStoreErrorFilter.Create(REGISTERED_SPAN_NAME, CanonicalCode.Cancelled, 0)); @@ -157,12 +161,16 @@ public void GetErrorSampledSpans_MaxSpansToReturn() { var span1 = CreateSampledSpan(REGISTERED_SPAN_NAME) as Span; interval += TimeSpan.FromTicks(10); - span1.End(EndSpanOptions.Builder().SetStatus(Status.Cancelled).Build()); + span1.Status = Status.Cancelled; + span1.End(); + // Advance time to allow other spans to be sampled. interval += TimeSpan.FromSeconds(5); var span2 = CreateSampledSpan(REGISTERED_SPAN_NAME) as Span; interval += TimeSpan.FromTicks(10); - span2.End(EndSpanOptions.Builder().SetStatus(Status.Cancelled).Build()); + span2.Status = Status.Cancelled; + span2.End(); + var samples = sampleStore.GetErrorSampledSpans( SampledSpanStoreErrorFilter.Create(REGISTERED_SPAN_NAME, CanonicalCode.Cancelled, 1)); @@ -176,10 +184,15 @@ public void GetErrorSampledSpans_NullCode() { var span1 = CreateSampledSpan(REGISTERED_SPAN_NAME) as Span; interval += TimeSpan.FromTicks(10); - span1.End(EndSpanOptions.Builder().SetStatus(Status.Cancelled).Build()); + + span1.Status = Status.Cancelled;; + span1.End(); + var span2 = CreateSampledSpan(REGISTERED_SPAN_NAME) as Span; interval += TimeSpan.FromTicks(10); - span2.End(EndSpanOptions.Builder().SetStatus(Status.Unknown).Build()); + span2.Status = Status.Unknown; + span2.End(); + var samples = sampleStore.GetErrorSampledSpans(SampledSpanStoreErrorFilter.Create(REGISTERED_SPAN_NAME, null, 0)); Assert.Equal(2, samples.Count()); @@ -192,10 +205,13 @@ public void GetErrorSampledSpans_NullCode_MaxSpansToReturn() { var span1 = CreateSampledSpan(REGISTERED_SPAN_NAME) as Span; interval += TimeSpan.FromTicks(10); - span1.End(EndSpanOptions.Builder().SetStatus(Status.Cancelled).Build()); + span1.Status = Status.Cancelled; + span1.End(); var span2 = CreateSampledSpan(REGISTERED_SPAN_NAME) as Span; interval += TimeSpan.FromTicks(10); - span2.End(EndSpanOptions.Builder().SetStatus(Status.Unknown).Build()); + span2.Status = Status.Unknown; + span2.End(); + var samples = sampleStore.GetErrorSampledSpans(SampledSpanStoreErrorFilter.Create(REGISTERED_SPAN_NAME, null, 1)); Assert.Single(samples); @@ -356,8 +372,11 @@ private void AddSpanNameToAllErrorBuckets(String spanName) var sampledSpan = CreateSampledSpan(spanName); var notSampledSpan = CreateNotSampledSpan(spanName); interval += TimeSpan.FromTicks(10); - sampledSpan.End(EndSpanOptions.Builder().SetStatus(code.ToStatus()).Build()); - notSampledSpan.End(EndSpanOptions.Builder().SetStatus(code.ToStatus()).Build()); + + sampledSpan.Status = code.ToStatus(); + notSampledSpan.Status = code.ToStatus(); + sampledSpan.End(); + notSampledSpan.End(); } } } diff --git a/test/OpenTelemetry.Tests/Impl/Trace/NoopSpanBuilderTests.cs b/test/OpenTelemetry.Tests/Impl/Trace/NoopSpanBuilderTests.cs new file mode 100644 index 00000000000..e3d1b17349e --- /dev/null +++ b/test/OpenTelemetry.Tests/Impl/Trace/NoopSpanBuilderTests.cs @@ -0,0 +1,47 @@ +// +// Copyright 2018, OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; + +namespace OpenTelemetry.Tests.Impl.Trace +{ + using OpenTelemetry.Trace; + using Xunit; + + public class NoopSpanBuilderTests + { + [Fact] + public void NoopSpanBuilder_BadArguments() + { + Assert.Throws(() => new NoopSpanBuilder(null)); + + var spanBuilder = new NoopSpanBuilder("foo"); + Assert.Throws(() => spanBuilder.SetParent((ISpan)null)); + Assert.Throws(() => spanBuilder.SetParent((SpanContext)null)); + Assert.Throws(() => spanBuilder.SetSampler(null)); + Assert.Throws(() => spanBuilder.AddLink((ILink)null)); + Assert.Throws(() => spanBuilder.AddLink((SpanContext)null)); + Assert.Throws(() => spanBuilder.AddLink(null, null)); + Assert.Throws(() => spanBuilder.AddLink(SpanContext.Blank, null)); + } + + [Fact] + public void NoopSpanBuilder_Ok() + { + Assert.Same(BlankSpan.Instance, new NoopSpanBuilder("foo").StartSpan()); + } + } +} diff --git a/test/OpenTelemetry.Tests/Impl/Trace/NoopTracerTests.cs b/test/OpenTelemetry.Tests/Impl/Trace/NoopTracerTests.cs new file mode 100644 index 00000000000..b1e38a0ce44 --- /dev/null +++ b/test/OpenTelemetry.Tests/Impl/Trace/NoopTracerTests.cs @@ -0,0 +1,66 @@ +// +// Copyright 2018, OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using OpenTelemetry.Resources; + +namespace OpenTelemetry.Tests.Impl.Trace +{ + using System; + using OpenTelemetry.Common; + using OpenTelemetry.Context.Propagation; + using OpenTelemetry.Trace; + using Xunit; + + public class NoopTracerTests + { + [Fact] + public void NoopTracer_CurrentSpan() + { + Assert.Same(BlankSpan.Instance, NoopTracer.Instance.CurrentSpan); + } + + [Fact] + public void NoopTracer_WithSpan() + { + Assert.Same(NoopScope.Instance, NoopTracer.Instance.WithSpan(BlankSpan.Instance)); + } + + [Fact] + public void NoopTracer_SpanBuilder() + { + Assert.IsType(NoopTracer.Instance.SpanBuilder("foo")); + } + + [Fact] + public void NoopTracer_Formats() + { + Assert.NotNull(NoopTracer.Instance.TextFormat); + Assert.NotNull(NoopTracer.Instance.BinaryFormat); + Assert.IsAssignableFrom(NoopTracer.Instance.TextFormat); + Assert.IsAssignableFrom(NoopTracer.Instance.BinaryFormat); + } + + [Fact] + public void NoopTracer_RecordData() + { + Assert.Throws(() => NoopTracer.Instance.RecordSpanData(null)); + + // does not throw + NoopTracer.Instance.RecordSpanData(SpanData.Create(SpanContext.Blank, null, Resource.Empty, "foo", Timestamp.Zero, null, null, null, null, Status.Ok, SpanKind.Internal, Timestamp.Zero)); + } + } +} + diff --git a/test/OpenTelemetry.Tests/Impl/Trace/Propagation/TraceContextTest.cs b/test/OpenTelemetry.Tests/Impl/Trace/Propagation/TraceContextTest.cs index 4fd3835291b..9e322ebbb5b 100644 --- a/test/OpenTelemetry.Tests/Impl/Trace/Propagation/TraceContextTest.cs +++ b/test/OpenTelemetry.Tests/Impl/Trace/Propagation/TraceContextTest.cs @@ -29,12 +29,15 @@ public void TraceContextFormatCanParseExampleFromSpec() { var headers = new Dictionary() { - { "traceparent", "00-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01" }, - { "tracestate", "congo=lZWRzIHRoNhcm5hbCBwbGVhc3VyZS4,rojo=00-0af7651916cd43dd8448eb211c80319c-00f067aa0ba902b7-01" }, + {"traceparent", "00-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01"}, + { + "tracestate", + "congo=lZWRzIHRoNhcm5hbCBwbGVhc3VyZS4,rojo=00-0af7651916cd43dd8448eb211c80319c-00f067aa0ba902b7-01" + }, }; var f = new TraceContextFormat(); - var ctx = f.Extract(headers, (h, n) => new string[] { h[n] } ); + var ctx = f.Extract(headers, (h, n) => new string[] {h[n]}); Assert.Equal(TraceId.FromLowerBase16("0af7651916cd43dd8448eb211c80319c"), ctx.TraceId); Assert.Equal(SpanId.FromLowerBase16("b9c7c989f97918e1"), ctx.SpanId); @@ -52,5 +55,30 @@ public void TraceContextFormatCanParseExampleFromSpec() Assert.Equal("rojo", last.Key); Assert.Equal("00-0af7651916cd43dd8448eb211c80319c-00f067aa0ba902b7-01", last.Value); } + + [Fact] + public void TraceContextFormat_IsBlankIfNoHeader() + { + var headers = new Dictionary(); + + var f = new TraceContextFormat(); + var ctx = f.Extract(headers, (h, n) => new string[] { h[n] }); + + Assert.Same(SpanContext.Blank, ctx); + } + + [Fact] + public void TraceContextFormat_IsBlankIfInvalid() + { + var headers = new Dictionary + { + {"traceparent", "00-xyz7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01"} + }; + + var f = new TraceContextFormat(); + var ctx = f.Extract(headers, (h, n) => new string[] { h[n] }); + + Assert.Same(SpanContext.Blank, ctx); + } } } diff --git a/test/OpenTelemetry.Tests/Impl/Trace/Sampler/SamplersTest.cs b/test/OpenTelemetry.Tests/Impl/Trace/Sampler/SamplersTest.cs index 417ef6ffd3b..74f3d80dd65 100644 --- a/test/OpenTelemetry.Tests/Impl/Trace/Sampler/SamplersTest.cs +++ b/test/OpenTelemetry.Tests/Impl/Trace/Sampler/SamplersTest.cs @@ -33,7 +33,7 @@ public class SamplersTest private readonly SpanId spanId; private readonly SpanContext sampledSpanContext; private readonly SpanContext notSampledSpanContext; - private readonly ISpan sampledSpan; + private readonly ILink sampledLink; public SamplersTest() { @@ -42,7 +42,7 @@ public SamplersTest() spanId = SpanId.GenerateRandomId(random); sampledSpanContext = SpanContext.Create(traceId, parentSpanId, TraceOptions.Builder().SetIsSampled(true).Build(), Tracestate.Empty); notSampledSpanContext = SpanContext.Create(traceId, parentSpanId, TraceOptions.Default, Tracestate.Empty); - sampledSpan = new TestSpan(sampledSpanContext, SpanOptions.RecordEvents); + sampledLink = Link.FromSpanContext(sampledSpanContext); } [Fact] @@ -56,7 +56,7 @@ public void AlwaysSampleSampler_AlwaysReturnTrue() traceId, spanId, "Another name", - new List())); + null)); // Not sampled parent. Assert.True( @@ -66,7 +66,7 @@ public void AlwaysSampleSampler_AlwaysReturnTrue() traceId, spanId, "Yet another name", - new List())); + null)); } @@ -87,7 +87,7 @@ public void NeverSampleSampler_AlwaysReturnFalse() traceId, spanId, "bar", - new List())); + null)); // Not sampled parent. Assert.False( Samplers.NeverSample @@ -96,7 +96,7 @@ public void NeverSampleSampler_AlwaysReturnFalse() traceId, spanId, "quux", - new List())); + null)); } [Fact] @@ -123,19 +123,19 @@ public void ProbabilitySampler_DifferentProbabilities_NotSampledParent() { ISampler neverSample = ProbabilitySampler.Create(0.0); AssertSamplerSamplesWithProbability( - neverSample, notSampledSpanContext, new List(), 0.0); + neverSample, notSampledSpanContext, null, 0.0); ISampler alwaysSample = ProbabilitySampler.Create(1.0); AssertSamplerSamplesWithProbability( - alwaysSample, notSampledSpanContext, new List(), 1.0); + alwaysSample, notSampledSpanContext, null, 1.0); ISampler fiftyPercentSample = ProbabilitySampler.Create(0.5); AssertSamplerSamplesWithProbability( - fiftyPercentSample, notSampledSpanContext, new List(), 0.5); + fiftyPercentSample, notSampledSpanContext, null, 0.5); ISampler twentyPercentSample = ProbabilitySampler.Create(0.2); AssertSamplerSamplesWithProbability( - twentyPercentSample, notSampledSpanContext, new List(), 0.2); + twentyPercentSample, notSampledSpanContext, null, 0.2); ISampler twoThirdsSample = ProbabilitySampler.Create(2.0 / 3.0); AssertSamplerSamplesWithProbability( - twoThirdsSample, notSampledSpanContext, new List(), 2.0 / 3.0); + twoThirdsSample, notSampledSpanContext, null, 2.0 / 3.0); } [Fact] @@ -143,19 +143,19 @@ public void ProbabilitySampler_DifferentProbabilities_SampledParent() { ISampler neverSample = ProbabilitySampler.Create(0.0); AssertSamplerSamplesWithProbability( - neverSample, sampledSpanContext, new List(), 1.0); + neverSample, sampledSpanContext, null, 1.0); ISampler alwaysSample = ProbabilitySampler.Create(1.0); AssertSamplerSamplesWithProbability( - alwaysSample, sampledSpanContext, new List(), 1.0); + alwaysSample, sampledSpanContext, null, 1.0); ISampler fiftyPercentSample = ProbabilitySampler.Create(0.5); AssertSamplerSamplesWithProbability( - fiftyPercentSample, sampledSpanContext, new List(), 1.0); + fiftyPercentSample, sampledSpanContext, null, 1.0); ISampler twentyPercentSample = ProbabilitySampler.Create(0.2); AssertSamplerSamplesWithProbability( - twentyPercentSample, sampledSpanContext, new List(), 1.0); + twentyPercentSample, sampledSpanContext, null, 1.0); ISampler twoThirdsSample = ProbabilitySampler.Create(2.0 / 3.0); AssertSamplerSamplesWithProbability( - twoThirdsSample, sampledSpanContext, new List(), 1.0); + twoThirdsSample, sampledSpanContext, null, 1.0); } [Fact] @@ -163,19 +163,19 @@ public void ProbabilitySampler_DifferentProbabilities_SampledParentLink() { ISampler neverSample = ProbabilitySampler.Create(0.0); AssertSamplerSamplesWithProbability( - neverSample, notSampledSpanContext, new List() { sampledSpan }, 1.0); + neverSample, notSampledSpanContext, new List() { sampledLink }, 1.0); ISampler alwaysSample = ProbabilitySampler.Create(1.0); AssertSamplerSamplesWithProbability( - alwaysSample, notSampledSpanContext, new List() { sampledSpan }, 1.0); + alwaysSample, notSampledSpanContext, new List() { sampledLink }, 1.0); ISampler fiftyPercentSample = ProbabilitySampler.Create(0.5); AssertSamplerSamplesWithProbability( - fiftyPercentSample, notSampledSpanContext, new List() { sampledSpan }, 1.0); + fiftyPercentSample, notSampledSpanContext, new List() { sampledLink }, 1.0); ISampler twentyPercentSample = ProbabilitySampler.Create(0.2); AssertSamplerSamplesWithProbability( - twentyPercentSample, notSampledSpanContext, new List() { sampledSpan }, 1.0); + twentyPercentSample, notSampledSpanContext, new List() { sampledLink }, 1.0); ISampler twoThirdsSample = ProbabilitySampler.Create(2.0 / 3.0); AssertSamplerSamplesWithProbability( - twoThirdsSample, notSampledSpanContext, new List() { sampledSpan }, 1.0); + twoThirdsSample, notSampledSpanContext, new List() { sampledLink }, 1.0); } [Fact] @@ -211,7 +211,7 @@ public void ProbabilitySampler_SampleBasedOnTraceId() notSampledtraceId, SpanId.GenerateRandomId(random), SPAN_NAME, - new List())); + null)); // This traceId will be sampled by the ProbabilitySampler because the first 8 bytes as long // is less than probability * Long.MAX_VALUE; var sampledtraceId = @@ -241,7 +241,7 @@ public void ProbabilitySampler_SampleBasedOnTraceId() sampledtraceId, SpanId.GenerateRandomId(random), SPAN_NAME, - new List())); + null)); } [Fact] @@ -259,7 +259,7 @@ public void ProbabilitySampler_ToString() // Applies the given sampler to NUM_SAMPLE_TRIES random traceId/spanId pairs. private static void AssertSamplerSamplesWithProbability( - ISampler sampler, SpanContext parent, IEnumerable parentLinks, double probability) + ISampler sampler, SpanContext parent, List links, double probability) { var random = new RandomGenerator(1234); var count = 0; // Count of spans with sampling enabled @@ -270,7 +270,7 @@ private static void AssertSamplerSamplesWithProbability( TraceId.GenerateRandomId(random), SpanId.GenerateRandomId(random), SPAN_NAME, - parentLinks)) + links)) { count++; } diff --git a/test/OpenTelemetry.Tests/Impl/Trace/SpanBaseTest.cs b/test/OpenTelemetry.Tests/Impl/Trace/SpanBaseTest.cs deleted file mode 100644 index 964c0d6a1e0..00000000000 --- a/test/OpenTelemetry.Tests/Impl/Trace/SpanBaseTest.cs +++ /dev/null @@ -1,101 +0,0 @@ -// -// Copyright 2018, OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -namespace OpenTelemetry.Trace.Test -{ - using System; - using Moq; - using OpenTelemetry.Trace.Internal; - using Xunit; - - public class SpanBaseTest - { - private readonly RandomGenerator random; - private readonly SpanContext spanContext; - private readonly SpanContext notSampledSpanContext; - private readonly SpanOptions spanOptions; - - public SpanBaseTest() - { - random = new RandomGenerator(1234); - spanContext = - SpanContext.Create( - TraceId.GenerateRandomId(random), - SpanId.GenerateRandomId(random), - TraceOptions.Builder().SetIsSampled(true).Build(), Tracestate.Empty); - notSampledSpanContext = - SpanContext.Create( - TraceId.GenerateRandomId(random), - SpanId.GenerateRandomId(random), - TraceOptions.Default, Tracestate.Empty); - spanOptions = SpanOptions.RecordEvents; - } - - [Fact] - public void NewSpan_WithNullContext() - { - Assert.Throws(() => new TestSpan(null, default(SpanOptions))); - } - - - [Fact] - public void GetOptions_WhenNullOptions() - { - var span = new TestSpan(notSampledSpanContext, default(SpanOptions)); - Assert.Equal(SpanOptions.None, span.Options); - } - - [Fact] - public void GetContextAndOptions() - { - var span = new TestSpan(spanContext, spanOptions); - Assert.Equal(spanContext, span.Context); - Assert.Equal(spanOptions, span.Options); - } - - [Fact] - public void PutAttributeCallsAddAttributeByDefault() - { - var mockSpan = new Mock(spanContext, spanOptions) { CallBase = true }; - var span = mockSpan.Object; - IAttributeValue val = AttributeValue.Create(true); - span.SetAttribute("MyKey", val); - span.End(); - mockSpan.Verify((s) => s.SetAttribute(It.Is((arg) => arg == "MyKey"), It.Is((v) => v == val))); - } - - [Fact] - public void EndCallsEndWithDefaultOptions() - { - var mockSpan = new Mock(spanContext, spanOptions) { CallBase = true }; - var span = mockSpan.Object; - span.End(); - mockSpan.Verify((s) => s.End(EndSpanOptions.Default)); - } - - [Fact] - public void AddEventDefaultImplementation() - { - var mockSpan = new Mock(); - var span = mockSpan.Object; - - var @event = Event.Create("MyEvent"); - span.AddEvent(@event); - - mockSpan.Verify((s) => s.AddEvent(@event)); - } - } -} diff --git a/test/OpenTelemetry.Tests/Impl/Trace/SpanBuilderBaseTest.cs b/test/OpenTelemetry.Tests/Impl/Trace/SpanBuilderBaseTest.cs deleted file mode 100644 index 7837f7ce898..00000000000 --- a/test/OpenTelemetry.Tests/Impl/Trace/SpanBuilderBaseTest.cs +++ /dev/null @@ -1,70 +0,0 @@ -// -// Copyright 2018, OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -namespace OpenTelemetry.Trace.Test -{ - using Moq; - using OpenTelemetry.Trace.Internal; - using Xunit; - - public class SpanBuilderBaseTest - { - private readonly ITracer tracer; - private readonly Mock spanBuilder = new Mock(SpanKind.Internal); - private readonly Mock span = new Mock(); - - public SpanBuilderBaseTest() - { - tracer = Tracing.Tracer; - spanBuilder.Setup((b) => b.StartSpan()).Returns(span.Object); - } - - [Fact] - public void StartScopedSpan() - { - Assert.Same(BlankSpan.Instance, tracer.CurrentSpan); - var scope = spanBuilder.Object.StartScopedSpan(); - try - { - Assert.Same(span.Object, tracer.CurrentSpan); - } - finally - { - scope.Dispose(); - } - span.Verify(s => s.End(EndSpanOptions.Default)); - Assert.Same(BlankSpan.Instance, tracer.CurrentSpan); - } - - [Fact] - public void StartScopedSpan_WithParam() - { - Assert.Same(BlankSpan.Instance, tracer.CurrentSpan); - - var scope = spanBuilder.Object.StartScopedSpan(out var outSpan); - try - { - Assert.Same(outSpan, tracer.CurrentSpan); - } - finally - { - scope.Dispose(); - } - span.Verify(s => s.End(EndSpanOptions.Default)); - Assert.Same(BlankSpan.Instance, tracer.CurrentSpan); - } - } -} diff --git a/test/OpenTelemetry.Tests/Impl/Trace/SpanBuilderTest.cs b/test/OpenTelemetry.Tests/Impl/Trace/SpanBuilderTest.cs index 48cec0cc764..135efbb4042 100644 --- a/test/OpenTelemetry.Tests/Impl/Trace/SpanBuilderTest.cs +++ b/test/OpenTelemetry.Tests/Impl/Trace/SpanBuilderTest.cs @@ -17,7 +17,6 @@ namespace OpenTelemetry.Trace.Test { using System; - using System.Collections.Generic; using Moq; using OpenTelemetry.Common; using OpenTelemetry.Trace.Config; @@ -26,7 +25,7 @@ namespace OpenTelemetry.Trace.Test public class SpanBuilderTest { - private static readonly String SPAN_NAME = "MySpanName"; + private static readonly string SpanName = "MySpanName"; private readonly SpanBuilderOptions spanBuilderOptions; private readonly TraceParams alwaysSampleTraceParams = TraceParams.Default.ToBuilder().SetSampler(Samplers.AlwaysSample).Build(); private readonly IRandomGenerator randomHandler = new FakeRandomHandler(); @@ -46,25 +45,108 @@ public SpanBuilderTest() [Fact] public void StartSpanNullParent() { - var span = - SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, (ISpan)null, spanBuilderOptions).StartSpan(); + var span = new SpanBuilder(SpanName, spanBuilderOptions) + .SetSpanKind(SpanKind.Internal) + .SetNoParent() + .StartSpan(); Assert.True(span.Context.IsValid); Assert.True(span.IsRecordingEvents); Assert.True(span.Context.TraceOptions.IsSampled); var spanData = ((Span)span).ToSpanData(); Assert.Null(spanData.ParentSpanId); Assert.InRange(spanData.StartTimestamp, Timestamp.FromDateTimeOffset(DateTimeOffset.Now).AddDuration(Duration.Create(-1, 0)), Timestamp.FromDateTimeOffset(DateTimeOffset.Now).AddDuration(Duration.Create(1, 0))); - Assert.Equal(SPAN_NAME, spanData.Name); + Assert.Equal(SpanName, spanData.Name); + } + + [Fact] + public void StartSpanLastParentWins1() + { + var spanContext = + SpanContext.Create( + TraceId.GenerateRandomId(randomHandler), + SpanId.GenerateRandomId(randomHandler), + TraceOptions.Default, Tracestate.Empty); + + var span = (Span) new SpanBuilder(SpanName, spanBuilderOptions) + .SetNoParent() + .SetParent(spanContext) + .StartSpan(); + + Assert.True(span.Context.IsValid); + Assert.Equal(spanContext.TraceId, span.Context.TraceId); + Assert.Equal(spanContext.SpanId, span.ParentSpanId); + } + + [Fact] + public void StartSpanLastParentWins2() + { + var spanContext = + SpanContext.Create( + TraceId.GenerateRandomId(randomHandler), + SpanId.GenerateRandomId(randomHandler), + TraceOptions.Default, Tracestate.Empty); + + var span = (Span)new SpanBuilder(SpanName, spanBuilderOptions) + .SetParent(spanContext) + .SetNoParent() + .StartSpan(); + + Assert.True(span.Context.IsValid); + Assert.NotEqual(spanContext.TraceId, span.Context.TraceId); + Assert.Null(span.ParentSpanId); + } + + [Fact] + public void StartSpanLastParentWins3() + { + var spanContext = + SpanContext.Create( + TraceId.GenerateRandomId(randomHandler), + SpanId.GenerateRandomId(randomHandler), + TraceOptions.Default, Tracestate.Empty); + var rootSpan = (Span)new SpanBuilder(SpanName, spanBuilderOptions) + .StartSpan(); + + var childSpan = (Span)new SpanBuilder(SpanName, spanBuilderOptions) + .SetParent(spanContext) + .SetParent(rootSpan) + .StartSpan(); + + Assert.True(childSpan.Context.IsValid); + Assert.Equal(rootSpan.Context.TraceId, childSpan.Context.TraceId); + Assert.Equal(rootSpan.Context.SpanId, childSpan.ParentSpanId); + } + + [Fact] + public void StartSpanLastParentWins4() + { + var spanContext = + SpanContext.Create( + TraceId.GenerateRandomId(randomHandler), + SpanId.GenerateRandomId(randomHandler), + TraceOptions.Default, Tracestate.Empty); + var rootSpan = (Span)new SpanBuilder(SpanName, spanBuilderOptions) + .StartSpan(); + + var childSpan = (Span)new SpanBuilder(SpanName, spanBuilderOptions) + .SetParent(rootSpan) + .SetParent(spanContext) + .StartSpan(); + + Assert.True(childSpan.Context.IsValid); + Assert.Equal(spanContext.TraceId, childSpan.Context.TraceId); + Assert.Equal(spanContext.SpanId, childSpan.ParentSpanId); } [Fact] public void StartSpanNullParentWithRecordEvents() { - var span = - SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, (ISpan)null, spanBuilderOptions) - .SetSampler(Samplers.NeverSample) - .SetRecordEvents(true) - .StartSpan(); + var span = new SpanBuilder(SpanName, spanBuilderOptions) + .SetSpanKind(SpanKind.Internal) + .SetSampler(Samplers.NeverSample) + .SetRecordEvents(true) + .SetNoParent() + .StartSpan(); Assert.True(span.Context.IsValid); Assert.True(span.IsRecordingEvents); Assert.False(span.Context.TraceOptions.IsSampled); @@ -75,10 +157,11 @@ public void StartSpanNullParentWithRecordEvents() [Fact] public void StartSpanNullParentNoRecordOptions() { - var span = - SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, (ISpan)null, spanBuilderOptions) - .SetSampler(Samplers.NeverSample) - .StartSpan(); + var span = new SpanBuilder(SpanName, spanBuilderOptions) + .SetSpanKind(SpanKind.Internal) + .SetSampler(Samplers.NeverSample) + .SetNoParent() + .StartSpan(); Assert.True(span.Context.IsValid); Assert.False(span.IsRecordingEvents); Assert.False(span.Context.TraceOptions.IsSampled); @@ -87,13 +170,19 @@ public void StartSpanNullParentNoRecordOptions() [Fact] public void StartChildSpan() { - var rootSpan = - SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, (ISpan)null, spanBuilderOptions).StartSpan(); + var rootSpan = new SpanBuilder(SpanName, spanBuilderOptions) + .SetSpanKind(SpanKind.Internal) + .SetNoParent() + .StartSpan(); Assert.True(rootSpan.Context.IsValid); Assert.True(rootSpan.IsRecordingEvents); Assert.True(rootSpan.Context.TraceOptions.IsSampled); - var childSpan = - SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, rootSpan, spanBuilderOptions).StartSpan(); + + var childSpan = new SpanBuilder(SpanName, spanBuilderOptions) + .SetSpanKind(Trace.SpanKind.Internal) + .SetParent(rootSpan) + .StartSpan(); + Assert.True(childSpan.Context.IsValid); Assert.Equal(rootSpan.Context.TraceId, childSpan.Context.TraceId); Assert.Equal(rootSpan.Context.SpanId, ((Span)childSpan).ToSpanData().ParentSpanId); @@ -101,10 +190,13 @@ public void StartChildSpan() } [Fact] - public void StartSpan_NullParent() + public void StartSpan_ExplicitNoParent() { - var span = - SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, (SpanContext)null, spanBuilderOptions).StartSpan(); + var span = new SpanBuilder(SpanName, spanBuilderOptions) + .SetSpanKind(SpanKind.Internal) + .SetNoParent() + .StartSpan(); + Assert.True(span.Context.IsValid); Assert.True(span.IsRecordingEvents); Assert.True(span.Context.TraceOptions.IsSampled); @@ -113,11 +205,59 @@ public void StartSpan_NullParent() } [Fact] - public void StartSpanInvalidParent() + public void StartSpan_NoParent() { - var span = - SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, SpanContext.Blank, spanBuilderOptions) + var span = new SpanBuilder(SpanName, spanBuilderOptions) + .SetSpanKind(SpanKind.Internal) + .StartSpan(); + + Assert.True(span.Context.IsValid); + Assert.True(span.IsRecordingEvents); + Assert.True(span.Context.TraceOptions.IsSampled); + var spanData = ((Span)span).ToSpanData(); + Assert.Null(spanData.ParentSpanId); + } + + [Fact] + public void StartSpan_CurrentSpanParent() + { + var rootSpan = new SpanBuilder(SpanName, spanBuilderOptions) + .StartSpan(); + using (CurrentSpanUtils.WithSpan(rootSpan, true)) + { + var childSpan = (Span) new SpanBuilder(SpanName, spanBuilderOptions) + .StartSpan(); + + Assert.True(childSpan.Context.IsValid); + Assert.Equal(rootSpan.Context.TraceId, childSpan.Context.TraceId); + Assert.Equal(rootSpan.Context.SpanId, childSpan.ParentSpanId); + } + } + + [Fact] + public void StartSpan_NoParentInScopeOfCurrentSpan() + { + var rootSpan = new SpanBuilder(SpanName, spanBuilderOptions) + .StartSpan(); + using (CurrentSpanUtils.WithSpan(rootSpan, true)) + { + var childSpan = (Span)new SpanBuilder(SpanName, spanBuilderOptions) + .SetNoParent() .StartSpan(); + + Assert.True(childSpan.Context.IsValid); + Assert.NotEqual(rootSpan.Context.TraceId, childSpan.Context.TraceId); + Assert.Null(childSpan.ParentSpanId); + } + } + + [Fact] + public void StartSpanInvalidParent() + { + var span = new SpanBuilder(SpanName, spanBuilderOptions) + .SetSpanKind(SpanKind.Internal) + .SetParent(SpanContext.Blank) + .StartSpan(); Assert.True(span.Context.IsValid); Assert.True(span.IsRecordingEvents); Assert.True(span.Context.TraceOptions.IsSampled); @@ -133,10 +273,13 @@ public void StartRemoteSpan() TraceId.GenerateRandomId(randomHandler), SpanId.GenerateRandomId(randomHandler), TraceOptions.Default, Tracestate.Empty); - var span = - SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, spanContext, spanBuilderOptions) - .SetRecordEvents(true) - .StartSpan(); + + var span = new SpanBuilder(SpanName, spanBuilderOptions) + .SetSpanKind(SpanKind.Internal) + .SetParent(spanContext) + .SetRecordEvents(true) + .StartSpan(); + Assert.True(span.Context.IsValid); Assert.Equal(spanContext.TraceId, span.Context.TraceId); Assert.False(span.Context.TraceOptions.IsSampled); @@ -148,10 +291,12 @@ public void StartRemoteSpan() public void StartRootSpan_WithSpecifiedSampler() { // Apply given sampler before default sampler for root spans. - var rootSpan = - SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, (ISpan)null, spanBuilderOptions) - .SetSampler(Samplers.NeverSample) - .StartSpan(); + var rootSpan = new SpanBuilder(SpanName, spanBuilderOptions) + .SetSpanKind(SpanKind.Internal) + .SetNoParent() + .SetSampler(Samplers.NeverSample) + .StartSpan(); + Assert.True(rootSpan.Context.IsValid); Assert.False(rootSpan.Context.TraceOptions.IsSampled); } @@ -160,8 +305,11 @@ public void StartRootSpan_WithSpecifiedSampler() public void StartRootSpan_WithoutSpecifiedSampler() { // Apply default sampler (always true in the tests) for root spans. - var rootSpan = - SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, (ISpan)null, spanBuilderOptions).StartSpan(); + var rootSpan = new SpanBuilder(SpanName, spanBuilderOptions) + .SetSpanKind(SpanKind.Internal) + .SetNoParent() + .StartSpan(); + Assert.True(rootSpan.Context.IsValid); Assert.True(rootSpan.Context.TraceOptions.IsSampled); } @@ -169,17 +317,21 @@ public void StartRootSpan_WithoutSpecifiedSampler() [Fact] public void StartRemoteChildSpan_WithSpecifiedSampler() { - var rootSpan = - SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, (ISpan)null, spanBuilderOptions) - .SetSampler(Samplers.AlwaysSample) - .StartSpan(); + var rootSpan = new SpanBuilder(SpanName, spanBuilderOptions) + .SetSpanKind(SpanKind.Internal) + .SetSampler(Samplers.AlwaysSample) + .SetNoParent() + .StartSpan(); + Assert.True(rootSpan.Context.IsValid); Assert.True(rootSpan.Context.TraceOptions.IsSampled); // Apply given sampler before default sampler for spans with remote parent. - var childSpan = - SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, rootSpan.Context, spanBuilderOptions) - .SetSampler(Samplers.NeverSample) - .StartSpan(); + var childSpan = new SpanBuilder(SpanName, spanBuilderOptions) + .SetSpanKind(SpanKind.Internal) + .SetSampler(Samplers.NeverSample) + .SetParent(rootSpan.Context) + .StartSpan(); + Assert.True(childSpan.Context.IsValid); Assert.Equal(rootSpan.Context.TraceId, childSpan.Context.TraceId); Assert.False(childSpan.Context.TraceOptions.IsSampled); @@ -188,16 +340,20 @@ public void StartRemoteChildSpan_WithSpecifiedSampler() [Fact] public void StartRemoteChildSpan_WithoutSpecifiedSampler() { - var rootSpan = - SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, (ISpan)null, spanBuilderOptions) - .SetSampler(Samplers.NeverSample) - .StartSpan(); + var rootSpan = new SpanBuilder(SpanName, spanBuilderOptions) + .SetSpanKind(SpanKind.Internal) + .SetSampler(Samplers.NeverSample) + .SetNoParent() + .StartSpan(); + Assert.True(rootSpan.Context.IsValid); Assert.False(rootSpan.Context.TraceOptions.IsSampled); // Apply default sampler (always true in the tests) for spans with remote parent. - var childSpan = - SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, rootSpan.Context, spanBuilderOptions) - .StartSpan(); + var childSpan = new SpanBuilder(SpanName, spanBuilderOptions) + .SetSpanKind(SpanKind.Internal) + .SetParent(rootSpan.Context) + .StartSpan(); + Assert.True(childSpan.Context.IsValid); Assert.Equal(rootSpan.Context.TraceId, childSpan.Context.TraceId); Assert.False(childSpan.Context.TraceOptions.IsSampled); @@ -206,17 +362,22 @@ public void StartRemoteChildSpan_WithoutSpecifiedSampler() [Fact] public void StartChildSpan_WithSpecifiedSampler() { - var rootSpan = - SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, (ISpan)null, spanBuilderOptions) - .SetSampler(Samplers.AlwaysSample) - .StartSpan(); + var rootSpan = new SpanBuilder(SpanName, spanBuilderOptions) + .SetSpanKind(SpanKind.Internal) + .SetSampler(Samplers.AlwaysSample) + .SetNoParent() + .StartSpan(); + Assert.True(rootSpan.Context.IsValid); Assert.True(rootSpan.Context.TraceOptions.IsSampled); // Apply the given sampler for child spans. - var childSpan = - SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, rootSpan, spanBuilderOptions) - .SetSampler(Samplers.NeverSample) - .StartSpan(); + + var childSpan = new SpanBuilder(SpanName, spanBuilderOptions) + .SetSpanKind(SpanKind.Internal) + .SetSampler(Samplers.NeverSample) + .SetParent(rootSpan) + .StartSpan(); + Assert.True(childSpan.Context.IsValid); Assert.Equal(rootSpan.Context.TraceId, childSpan.Context.TraceId); Assert.False(childSpan.Context.TraceOptions.IsSampled); @@ -225,15 +386,20 @@ public void StartChildSpan_WithSpecifiedSampler() [Fact] public void StartChildSpan_WithoutSpecifiedSampler() { - var rootSpan = - SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, (ISpan)null, spanBuilderOptions) - .SetSampler(Samplers.NeverSample) - .StartSpan(); + var rootSpan = new SpanBuilder(SpanName, spanBuilderOptions) + .SetSpanKind(SpanKind.Internal) + .SetSampler(Samplers.NeverSample) + .SetNoParent() + .StartSpan(); + Assert.True(rootSpan.Context.IsValid); Assert.False(rootSpan.Context.TraceOptions.IsSampled); // Don't apply the default sampler (always true) for child spans. - var childSpan = - SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, rootSpan, spanBuilderOptions).StartSpan(); + var childSpan = new SpanBuilder(SpanName, spanBuilderOptions) + .SetSpanKind(SpanKind.Internal) + .SetParent(rootSpan) + .StartSpan(); + Assert.True(childSpan.Context.IsValid); Assert.Equal(rootSpan.Context.TraceId, childSpan.Context.TraceId); Assert.False(childSpan.Context.TraceOptions.IsSampled); @@ -242,21 +408,28 @@ public void StartChildSpan_WithoutSpecifiedSampler() [Fact] public void StartChildSpan_SampledLinkedParent() { - var rootSpanUnsampled = - SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, (ISpan)null, spanBuilderOptions) - .SetSampler(Samplers.NeverSample) - .StartSpan(); + var rootSpanUnsampled = new SpanBuilder(SpanName, spanBuilderOptions) + .SetSpanKind(SpanKind.Internal) + .SetSampler(Samplers.NeverSample) + .SetNoParent() + .StartSpan(); + Assert.False(rootSpanUnsampled.Context.TraceOptions.IsSampled); var rootSpanSampled = - SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, (ISpan)null, spanBuilderOptions) + new SpanBuilder(SpanName, spanBuilderOptions) + .SetSpanKind(SpanKind.Internal) .SetSampler(Samplers.AlwaysSample) + .SetNoParent() .StartSpan(); + Assert.True(rootSpanSampled.Context.TraceOptions.IsSampled); // Sampled because the linked parent is sampled. - var childSpan = - SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, rootSpanUnsampled, spanBuilderOptions) - .SetParentLinks(new List() { rootSpanSampled }) - .StartSpan(); + var childSpan = new SpanBuilder(SpanName, spanBuilderOptions) + .SetSpanKind(SpanKind.Internal) + .AddLink(Link.FromSpanContext(rootSpanSampled.Context)) + .SetParent(rootSpanUnsampled) + .StartSpan(); + Assert.True(childSpan.Context.IsValid); Assert.Equal(rootSpanUnsampled.Context.TraceId, childSpan.Context.TraceId); Assert.True(childSpan.Context.TraceOptions.IsSampled); @@ -293,15 +466,14 @@ public void StartRemoteChildSpan_WithProbabilitySamplerDefaultSampler() // If parent is sampled then the remote child must be sampled. var childSpan = - SpanBuilder.Create( - SPAN_NAME, - SpanKind.Internal, - SpanContext.Create( - traceId, - SpanId.GenerateRandomId(randomHandler), - TraceOptions.Builder().SetIsSampled(true).Build(), Tracestate.Empty), - spanBuilderOptions) + new SpanBuilder(SpanName, spanBuilderOptions) + .SetSpanKind(SpanKind.Internal) + .SetParent(SpanContext.Create( + traceId, + SpanId.GenerateRandomId(randomHandler), + TraceOptions.Builder().SetIsSampled(true).Build(), Tracestate.Empty)) .StartSpan(); + Assert.True(childSpan.Context.IsValid); Assert.Equal(traceId, childSpan.Context.TraceId); Assert.True(childSpan.Context.TraceOptions.IsSampled); @@ -311,21 +483,35 @@ public void StartRemoteChildSpan_WithProbabilitySamplerDefaultSampler() // If parent is not sampled then the remote child must be not sampled. childSpan = - SpanBuilder.Create( - SPAN_NAME, - SpanKind.Internal, - SpanContext.Create( - traceId, - SpanId.GenerateRandomId(randomHandler), - TraceOptions.Default, Tracestate.Empty), - spanBuilderOptions) + new SpanBuilder(SpanName, spanBuilderOptions) + .SetSpanKind(SpanKind.Internal) + .SetParent(SpanContext.Create( + traceId, + SpanId.GenerateRandomId(randomHandler), + TraceOptions.Default, + Tracestate.Empty)) .StartSpan(); + Assert.True(childSpan.Context.IsValid); Assert.Equal(traceId, childSpan.Context.TraceId); Assert.False(childSpan.Context.TraceOptions.IsSampled); childSpan.End(); } + [Fact] + public void SpanBuilder_BadArguments() + { + var spanBuilder = new SpanBuilder(SpanName, spanBuilderOptions); + + Assert.Throws(() => spanBuilder.SetParent((ISpan)null)); + Assert.Throws(() => spanBuilder.SetParent((SpanContext)null)); + Assert.Throws(() => spanBuilder.SetSampler(null)); + Assert.Throws(() => spanBuilder.AddLink((ILink)null)); + Assert.Throws(() => spanBuilder.AddLink((SpanContext)null)); + Assert.Throws(() => spanBuilder.AddLink(null, null)); + Assert.Throws(() => spanBuilder.AddLink(SpanContext.Blank, null)); + } + class FakeRandomHandler : IRandomGenerator { private readonly Random random; @@ -335,7 +521,7 @@ public FakeRandomHandler() this.random = new Random(1234); } - public Random current() + public Random Current() { return random; } diff --git a/test/OpenTelemetry.Tests/Impl/Trace/SpanTest.cs b/test/OpenTelemetry.Tests/Impl/Trace/SpanTest.cs index 9dddee99da3..369714c4dd9 100644 --- a/test/OpenTelemetry.Tests/Impl/Trace/SpanTest.cs +++ b/test/OpenTelemetry.Tests/Impl/Trace/SpanTest.cs @@ -47,7 +47,8 @@ public SpanTest() { timestamp = Timestamp.FromDateTimeOffset(startTime); timestampConverter = Timer.StartNew(startTime, () => interval); - spanContext = SpanContext.Create(TraceId.GenerateRandomId(random), SpanId.GenerateRandomId(random), OpenTelemetry.Trace.TraceOptions.Default, Tracestate.Empty); + spanContext = SpanContext.Create(TraceId.GenerateRandomId(random), SpanId.GenerateRandomId(random), + OpenTelemetry.Trace.TraceOptions.Default, Tracestate.Empty); parentSpanId = SpanId.GenerateRandomId(random); attributes.Add( "MyStringAttributeKey", AttributeValue.StringAttributeValue("MyStringAttributeValue")); @@ -77,6 +78,7 @@ public void ToSpanData_NoRecordEvents() { span.SetAttribute(attribute.Key, attribute.Value); } + span.AddEvent(Event.Create(EVENT_DESCRIPTION)); span.AddEvent(EVENT_DESCRIPTION, attributes); span.AddLink(Link.FromSpanContext(spanContext)); @@ -105,6 +107,7 @@ public void NoEventsRecordedAfterEnd() { span.SetAttribute(attribute.Key, attribute.Value); } + span.SetAttribute( "MySingleStringAttributeKey", AttributeValue.StringAttributeValue("MySingleStringAttributeValue")); @@ -133,7 +136,7 @@ public void ToSpanData_ActiveSpan() TraceParams.Default, startEndHandler, timestampConverter); - + span.SetAttribute( "MySingleStringAttributeKey", AttributeValue.StringAttributeValue("MySingleStringAttributeValue")); @@ -155,12 +158,14 @@ public void ToSpanData_ActiveSpan() Assert.Equal(SPAN_NAME, spanData.Name); Assert.Equal(parentSpanId, spanData.ParentSpanId); Assert.Equal(0, spanData.Attributes.DroppedAttributesCount); - Assert.Equal(expectedAttributes, spanData.Attributes.AttributeMap); + Assert.Equal(expectedAttributes, spanData.Attributes.AttributeMap); Assert.Equal(0, spanData.Events.DroppedEventsCount); Assert.Equal(2, spanData.Events.Events.Count()); - Assert.Equal(timestamp.AddDuration(Duration.Create(TimeSpan.FromMilliseconds(100))), spanData.Events.Events.ToList()[0].Timestamp); + Assert.Equal(timestamp.AddDuration(Duration.Create(TimeSpan.FromMilliseconds(100))), + spanData.Events.Events.ToList()[0].Timestamp); Assert.Equal(Event.Create(EVENT_DESCRIPTION), spanData.Events.Events.ToList()[0].Event); - Assert.Equal(timestamp.AddDuration(Duration.Create(TimeSpan.FromMilliseconds(200))), spanData.Events.Events.ToList()[1].Timestamp); + Assert.Equal(timestamp.AddDuration(Duration.Create(TimeSpan.FromMilliseconds(200))), + spanData.Events.Events.ToList()[1].Timestamp); Assert.Equal(Event.Create(EVENT_DESCRIPTION, attributes), spanData.Events.Events.ToList()[1].Event); Assert.Equal(0, spanData.Links.DroppedLinksCount); Assert.Single(spanData.Links.Links); @@ -170,8 +175,7 @@ public void ToSpanData_ActiveSpan() Assert.Null(spanData.EndTimestamp); var startEndMock = Mock.Get(startEndHandler); - var spanBase = span as SpanBase; - startEndMock.Verify(s => s.OnStart(spanBase), Times.Once); + startEndMock.Verify(s => s.OnStart(span), Times.Once); } [Fact] @@ -187,7 +191,7 @@ public void GoSpanData_EndedSpan() TraceParams.Default, startEndHandler, timestampConverter); - + span.SetAttribute( "MySingleStringAttributeKey", AttributeValue.StringAttributeValue("MySingleStringAttributeValue")); @@ -204,8 +208,9 @@ public void GoSpanData_EndedSpan() var link = Link.FromSpanContext(spanContext); span.AddLink(link); interval = TimeSpan.FromMilliseconds(400); - span.End(EndSpanOptions.Builder().SetStatus(Status.Cancelled).Build()); - + span.Status = Status.Cancelled; + span.End(); + var spanData = ((Span)span).ToSpanData(); Assert.Equal(spanContext, spanData.Context); Assert.Equal(SPAN_NAME, spanData.Name); @@ -214,9 +219,11 @@ public void GoSpanData_EndedSpan() Assert.Equal(expectedAttributes, spanData.Attributes.AttributeMap); Assert.Equal(0, spanData.Events.DroppedEventsCount); Assert.Equal(2, spanData.Events.Events.Count()); - Assert.Equal(timestamp.AddDuration(Duration.Create(TimeSpan.FromMilliseconds(100))), spanData.Events.Events.ToList()[0].Timestamp); + Assert.Equal(timestamp.AddDuration(Duration.Create(TimeSpan.FromMilliseconds(100))), + spanData.Events.Events.ToList()[0].Timestamp); Assert.Equal(Event.Create(EVENT_DESCRIPTION), spanData.Events.Events.ToList()[0].Event); - Assert.Equal(timestamp.AddDuration(Duration.Create(TimeSpan.FromMilliseconds(200))), spanData.Events.Events.ToList()[1].Timestamp); + Assert.Equal(timestamp.AddDuration(Duration.Create(TimeSpan.FromMilliseconds(200))), + spanData.Events.Events.ToList()[1].Timestamp); Assert.Equal(Event.Create(EVENT_DESCRIPTION, attributes), spanData.Events.Events.ToList()[1].Event); Assert.Equal(0, spanData.Links.DroppedLinksCount); Assert.Single(spanData.Links.Links); @@ -226,9 +233,8 @@ public void GoSpanData_EndedSpan() Assert.Equal(timestamp.AddDuration(Duration.Create(TimeSpan.FromMilliseconds(400))), spanData.EndTimestamp); var startEndMock = Mock.Get(startEndHandler); - var spanBase = span as SpanBase; - startEndMock.Verify(s => s.OnStart(spanBase), Times.Once); - startEndMock.Verify(s => s.OnEnd(spanBase), Times.Once); + startEndMock.Verify(s => s.OnStart(span), Times.Once); + startEndMock.Verify(s => s.OnEnd(span), Times.Once); } [Fact] @@ -252,8 +258,7 @@ public void Status_ViaSetStatus() Assert.Equal(Status.Cancelled, span.Status); var startEndMock = Mock.Get(startEndHandler); - var spanBase = span as SpanBase; - startEndMock.Verify(s => s.OnStart(spanBase), Times.Once); + startEndMock.Verify(s => s.OnStart(span), Times.Once); } [Fact] @@ -273,12 +278,12 @@ public void status_ViaEndSpanOptions() Assert.Equal(Status.Ok, span.Status); ((Span)span).Status = Status.Cancelled; Assert.Equal(Status.Cancelled, span.Status); - span.End(EndSpanOptions.Builder().SetStatus(Status.Aborted).Build()); + span.Status = Status.Aborted; + span.End(); Assert.Equal(Status.Aborted, span.Status); var startEndMock = Mock.Get(startEndHandler); - var spanBase = span as SpanBase; - startEndMock.Verify(s => s.OnStart(spanBase), Times.Once); + startEndMock.Verify(s => s.OnStart(span), Times.Once); } [Fact] @@ -307,6 +312,7 @@ public void DroppingAttributes() } } + var spanData = ((Span)span).ToSpanData(); Assert.Equal(maxNumberOfAttributes, spanData.Attributes.DroppedAttributesCount); Assert.Equal(maxNumberOfAttributes, spanData.Attributes.AttributeMap.Count); @@ -315,9 +321,10 @@ public void DroppingAttributes() Assert.Equal( AttributeValue.LongAttributeValue(i + maxNumberOfAttributes), spanData - .Attributes - .AttributeMap["MyStringAttributeKey" + (i + maxNumberOfAttributes)]); + .Attributes + .AttributeMap["MyStringAttributeKey" + (i + maxNumberOfAttributes)]); } + span.End(); spanData = ((Span)span).ToSpanData(); Assert.Equal(maxNumberOfAttributes, spanData.Attributes.DroppedAttributesCount); @@ -327,8 +334,8 @@ public void DroppingAttributes() Assert.Equal( AttributeValue.LongAttributeValue(i + maxNumberOfAttributes), spanData - .Attributes - .AttributeMap["MyStringAttributeKey" + (i + maxNumberOfAttributes)]); + .Attributes + .AttributeMap["MyStringAttributeKey" + (i + maxNumberOfAttributes)]); } } @@ -358,6 +365,7 @@ public void DroppingAndAddingAttributes() } } + var spanData = ((Span)span).ToSpanData(); Assert.Equal(maxNumberOfAttributes, spanData.Attributes.DroppedAttributesCount); Assert.Equal(maxNumberOfAttributes, spanData.Attributes.AttributeMap.Count); @@ -366,9 +374,10 @@ public void DroppingAndAddingAttributes() Assert.Equal( AttributeValue.LongAttributeValue(i + maxNumberOfAttributes), spanData - .Attributes - .AttributeMap["MyStringAttributeKey" + (i + maxNumberOfAttributes)]); + .Attributes + .AttributeMap["MyStringAttributeKey" + (i + maxNumberOfAttributes)]); } + for (var i = 0; i < maxNumberOfAttributes / 2; i++) { IDictionary attributes = new Dictionary(); @@ -379,6 +388,7 @@ public void DroppingAndAddingAttributes() } } + spanData = ((Span)span).ToSpanData(); Assert.Equal(maxNumberOfAttributes * 3 / 2, spanData.Attributes.DroppedAttributesCount); Assert.Equal(maxNumberOfAttributes, spanData.Attributes.AttributeMap.Count); @@ -388,13 +398,15 @@ public void DroppingAndAddingAttributes() Assert.Equal( AttributeValue.LongAttributeValue(i + maxNumberOfAttributes * 3 / 2), spanData - .Attributes - .AttributeMap["MyStringAttributeKey" + (i + maxNumberOfAttributes * 3 / 2)]); + .Attributes + .AttributeMap["MyStringAttributeKey" + (i + maxNumberOfAttributes * 3 / 2)]); } + // Test that we have the newest re-added initial entries. for (var i = 0; i < maxNumberOfAttributes / 2; i++) { - Assert.Equal(AttributeValue.LongAttributeValue(i), spanData.Attributes.AttributeMap["MyStringAttributeKey" + i]); + Assert.Equal(AttributeValue.LongAttributeValue(i), + spanData.Attributes.AttributeMap["MyStringAttributeKey" + i]); } } @@ -421,16 +433,20 @@ public void DroppingEvents() span.AddEvent(testEvent); interval += TimeSpan.FromMilliseconds(100); } + var spanData = ((Span)span).ToSpanData(); Assert.Equal(maxNumberOfEvents, spanData.Events.DroppedEventsCount); Assert.Equal(maxNumberOfEvents, spanData.Events.Events.Count()); i = 0; foreach (var te in spanData.Events.Events) { - Assert.Equal(timestamp.AddDuration(Duration.Create(TimeSpan.FromMilliseconds(100 * (maxNumberOfEvents + i)))), te.Timestamp); + Assert.Equal( + timestamp.AddDuration(Duration.Create(TimeSpan.FromMilliseconds(100 * (maxNumberOfEvents + i)))), + te.Timestamp); Assert.Equal(testEvent, te.Event); i++; } + span.End(); spanData = ((Span)span).ToSpanData(); Assert.Equal(maxNumberOfEvents, spanData.Events.DroppedEventsCount); @@ -438,7 +454,9 @@ public void DroppingEvents() i = 0; foreach (var te in spanData.Events.Events) { - Assert.Equal(timestamp.AddDuration(Duration.Create(TimeSpan.FromMilliseconds(100 * (maxNumberOfEvents + i)))), te.Timestamp); + Assert.Equal( + timestamp.AddDuration(Duration.Create(TimeSpan.FromMilliseconds(100 * (maxNumberOfEvents + i)))), + te.Timestamp); Assert.Equal(testEvent, te.Event); i++; } @@ -465,13 +483,15 @@ public void DroppingLinks() { span.AddLink(link); } + var spanData = ((Span)span).ToSpanData(); Assert.Equal(maxNumberOfLinks, spanData.Links.DroppedLinksCount); Assert.Equal(maxNumberOfLinks, spanData.Links.Links.Count()); foreach (var actualLink in spanData.Links.Links) - { + { Assert.Equal(link, actualLink); } + span.End(); spanData = ((Span)span).ToSpanData(); Assert.Equal(maxNumberOfLinks, spanData.Links.DroppedLinksCount); @@ -495,7 +515,8 @@ public void SampleToLocalSpanStore() TraceParams.Default, startEndHandler, timestampConverter); - span.End(EndSpanOptions.Builder().SetSampleToLocalSpanStore(true).Build()); + span.IsSampleToLocalSpanStore = true; + span.End(); Assert.True(((Span)span).IsSampleToLocalSpanStore); var span2 = @@ -513,10 +534,9 @@ public void SampleToLocalSpanStore() Assert.False(((Span)span2).IsSampleToLocalSpanStore); var startEndMock = Mock.Get(startEndHandler); - var spanBase = span as SpanBase; - startEndMock.Verify(s => s.OnEnd(spanBase), Times.Exactly(1)); - var spanBase2 = span2 as SpanBase; - startEndMock.Verify(s => s.OnEnd(spanBase2), Times.Exactly(1)); + + startEndMock.Verify(s => s.OnEnd(span), Times.Exactly(1)); + startEndMock.Verify(s => s.OnEnd(span2), Times.Exactly(1)); } [Fact] @@ -535,5 +555,51 @@ public void SampleToLocalSpanStore_RunningSpan() Assert.Throws(() => ((Span)span).IsSampleToLocalSpanStore); } + + [Fact] + public void BadArguments() + { + var span = + Span.StartSpan( + spanContext, + recordSpanOptions, + SPAN_NAME, + SpanKind.Internal, + parentSpanId, + TraceParams.Default, + startEndHandler, + timestampConverter); + + Assert.Throws(() => span.Status = null); + Assert.Throws(() => span.UpdateName(null)); + Assert.Throws(() => span.SetAttribute(null, string.Empty)); + Assert.Throws(() => span.SetAttribute(string.Empty, (IAttributeValue)null)); + Assert.Throws(() => + span.SetAttribute(null, AttributeValue.StringAttributeValue("foo"))); + Assert.Throws(() => span.SetAttribute(null, 1L)); + Assert.Throws(() => span.SetAttribute(null, 0.1d)); + Assert.Throws(() => span.SetAttribute(null, true)); + Assert.Throws(() => span.AddEvent((string)null)); + Assert.Throws(() => span.AddEvent((IEvent)null)); + Assert.Throws(() => span.AddLink(null)); + } + + [Fact] + public void SetSampleTo() + { + var span = (Span)Span.StartSpan( + spanContext, + recordSpanOptions, + SPAN_NAME, + SpanKind.Internal, + parentSpanId, + TraceParams.Default, + startEndHandler, + timestampConverter); + + span.IsSampleToLocalSpanStore = true; + span.End(); + Assert.True(span.IsSampleToLocalSpanStore); + } } } diff --git a/test/OpenTelemetry.Tests/Impl/Trace/TestSpan.cs b/test/OpenTelemetry.Tests/Impl/Trace/TestSpan.cs index f227affc1e0..9fbcd9ba9ad 100644 --- a/test/OpenTelemetry.Tests/Impl/Trace/TestSpan.cs +++ b/test/OpenTelemetry.Tests/Impl/Trace/TestSpan.cs @@ -19,68 +19,59 @@ namespace OpenTelemetry.Trace.Test using System; using System.Collections.Generic; - public class TestSpan : SpanBase + public class TestSpan : ISpan { - public TestSpan(SpanContext context, SpanOptions options) - : base(context, options) + public TestSpan() { } - public override DateTimeOffset EndTime { get; } - - public override TimeSpan Latency { get; } - - public override bool IsSampleToLocalSpanStore { get; } - - public override Status Status { get; set; } - - public override string Name { get; protected set; } - - public override SpanId ParentSpanId { get; } - - public override bool HasEnded => true; - - public override bool IsRecordingEvents => this.Options.HasFlag(SpanOptions.RecordEvents); + public SpanContext Context { get; } + public bool IsRecordingEvents { get; } + public Status Status { get; set; } + public bool HasEnded { get; } + public void UpdateName(string name) + { + throw new NotImplementedException(); + } - public override void AddEvent(string name, IDictionary attributes) + public void SetAttribute(string key, IAttributeValue value) { } - public override void AddEvent(IEvent addEvent) + public void SetAttribute(string key, string value) { } - public override void AddLink(ILink link) + public void SetAttribute(string key, long value) { } - public override void End(EndSpanOptions options) + public void SetAttribute(string key, double value) { } - public override void SetAttribute(string key, IAttributeValue value) + public void SetAttribute(string key, bool value) { } - public override void SetAttribute(string key, string value) + public void AddEvent(string name) { } - public override void SetAttribute(string key, long value) + public void AddEvent(string name, IDictionary attributes) { } - public override void SetAttribute(string key, double value) + public void AddEvent(IEvent newEvent) { } - public override void SetAttribute(string key, bool value) + public void AddLink(ILink link) { } - public override SpanData ToSpanData() + public void End() { - return null; } } } diff --git a/test/OpenTelemetry.Tests/Impl/Trace/TracerBaseTest.cs b/test/OpenTelemetry.Tests/Impl/Trace/TracerBaseTest.cs deleted file mode 100644 index 678905342e3..00000000000 --- a/test/OpenTelemetry.Tests/Impl/Trace/TracerBaseTest.cs +++ /dev/null @@ -1,182 +0,0 @@ -// -// Copyright 2018, OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -namespace OpenTelemetry.Trace.Test -{ - using System; - using Moq; - using OpenTelemetry.Trace.Internal; - using Xunit; - - public class TracerBaseTest - { - private static readonly ITracer noopTracer = TracerBase.NoopTracer; - private static readonly string SPAN_NAME = "MySpanName"; - private readonly TracerBase tracer = Mock.Of(); - private readonly SpanBuilderBase spanBuilder = new Mock(SpanKind.Internal).Object; - private readonly SpanBase span = Mock.Of(); - - public TracerBaseTest() - { - } - - [Fact] - public void DefaultGetCurrentSpan() - { - Assert.Equal(BlankSpan.Instance, noopTracer.CurrentSpan); - } - - [Fact] - public void WithSpan_NullSpan() - { - Assert.Throws(() => noopTracer.WithSpan(null)); - } - - [Fact] - public void GetCurrentSpan_WithSpan() - { - Assert.Same(BlankSpan.Instance, noopTracer.CurrentSpan); - var ws = noopTracer.WithSpan(span); - try - { - Assert.Same(span, noopTracer.CurrentSpan); - } - finally - { - ws.Dispose(); - } - Assert.Same(BlankSpan.Instance, noopTracer.CurrentSpan); - } - - // [Fact] - // public void wrapRunnable() - // { - // Runnable runnable; - // Assert.Equal(noopTracer.getCurrentSpan()).isSameAs(BlankSpan.Instance); - // runnable = - // tracer.withSpan( - // span, - // new Runnable() { - // @Override - // public void run() - // { - // Assert.Equal(noopTracer.getCurrentSpan()).isSameAs(span); - // } - // }); - // // When we run the runnable we will have the span in the current Context. - // runnable.run(); - // verifyZeroInteractions(span); - // Assert.Equal(noopTracer.getCurrentSpan()).isSameAs(BlankSpan.Instance); - // } - - // [Fact] - // public void wrapCallable() throws Exception - // { - // readonly Object ret = new Object(); - // Callable callable; - // Assert.Equal(noopTracer.getCurrentSpan()).isSameAs(BlankSpan.Instance); - // callable = - // tracer.withSpan( - // span, - // new Callable() { - // @Override - // public Object call() throws Exception - // { - // Assert.Equal(noopTracer.getCurrentSpan()).isSameAs(span); - // return ret; - // } - // }); - // // When we call the callable we will have the span in the current Context. - // Assert.Equal(callable.call()).isEqualTo(ret); - // verifyZeroInteractions(span); - // Assert.Equal(noopTracer.getCurrentSpan()).isSameAs(BlankSpan.Instance); - // } - - [Fact] - public void SpanBuilderWithName_NullName() - { - Assert.Throws(() => noopTracer.SpanBuilder(null)); - } - - [Fact] - public void DefaultSpanBuilderWithName() - { - Assert.Same(BlankSpan.Instance, noopTracer.SpanBuilder(SPAN_NAME).StartSpan()); - } - - [Fact] - public void SpanBuilderWithParentAndName_NullName() - { - Assert.Throws(() => noopTracer.SpanBuilderWithParent(name: null, parent: null)); - } - - [Fact] - public void DefaultSpanBuilderWithParentAndName() - { - Assert.Same(BlankSpan.Instance, noopTracer.SpanBuilderWithParent(SPAN_NAME, parent: null).StartSpan()); - } - - [Fact] - public void DefaultSpanBuilderWithParentContext_NullName() - { - Assert.Throws(() => noopTracer.SpanBuilderWithParentContext(null, parentContext: null)); - } - - [Fact] - public void DefaultSpanBuilderWithParentContext_NullParent() - { - Assert.Same(BlankSpan.Instance, noopTracer.SpanBuilderWithParentContext(SPAN_NAME, parentContext: null).StartSpan()); - } - - [Fact] - public void DefaultSpanBuilderWithParentContext() - { - Assert.Same(BlankSpan.Instance, noopTracer.SpanBuilderWithParentContext(SPAN_NAME, parentContext: SpanContext.Blank).StartSpan()); - } - - [Fact] - public void StartSpanWithParentFromContext() - { - var ws = tracer.WithSpan(span); - try - { - Assert.Same(span, tracer.CurrentSpan); - Mock.Get(tracer).Setup((tracer) => tracer.SpanBuilderWithParent(SPAN_NAME, SpanKind.Internal, span)).Returns(spanBuilder); - Assert.Same(spanBuilder, tracer.SpanBuilder(SPAN_NAME)); - } - finally - { - ws.Dispose(); - } - } - - [Fact] - public void StartSpanWithInvalidParentFromContext() - { - var ws = tracer.WithSpan(BlankSpan.Instance); - try - { - Assert.Same(BlankSpan.Instance, tracer.CurrentSpan); - Mock.Get(tracer).Setup((t) => t.SpanBuilderWithParent(SPAN_NAME, SpanKind.Internal, BlankSpan.Instance)).Returns(spanBuilder); - Assert.Same(spanBuilder, tracer.SpanBuilder(SPAN_NAME)); - } - finally - { - ws.Dispose(); - } - } - } -} diff --git a/test/OpenTelemetry.Tests/Impl/Trace/TracerTest.cs b/test/OpenTelemetry.Tests/Impl/Trace/TracerTest.cs index ef58992fa15..66f7fad7323 100644 --- a/test/OpenTelemetry.Tests/Impl/Trace/TracerTest.cs +++ b/test/OpenTelemetry.Tests/Impl/Trace/TracerTest.cs @@ -14,8 +14,11 @@ // limitations under the License. // +using OpenTelemetry.Trace.Sampler; + namespace OpenTelemetry.Trace.Test { + using System; using Moq; using OpenTelemetry.Trace.Config; using OpenTelemetry.Trace.Internal; @@ -23,7 +26,7 @@ namespace OpenTelemetry.Trace.Test public class TracerTest { - private const string SPAN_NAME = "MySpanName"; + private const string SpanName = "MySpanName"; private readonly IStartEndHandler startEndHandler; private readonly ITraceConfig traceConfig; private readonly Tracer tracer; @@ -39,15 +42,55 @@ public TracerTest() [Fact] public void CreateSpanBuilder() { - var spanBuilder = tracer.SpanBuilderWithParent(SPAN_NAME, parent: BlankSpan.Instance); + var spanBuilder = tracer.SpanBuilder(SpanName); Assert.IsType(spanBuilder); } [Fact] - public void CreateSpanBuilderWithRemoteParet() + public void CreateSpanBuilderWithNullName() { - var spanBuilder = tracer.SpanBuilderWithParentContext(SPAN_NAME, parentContext: SpanContext.Blank); - Assert.IsType(spanBuilder); + Assert.Throws(() => tracer.SpanBuilder(null)); + } + + [Fact] + public void GetCurrentSpanBlank() + { + Assert.Same(BlankSpan.Instance, tracer.CurrentSpan); + } + + [Fact] + public void GetCurrentSpan() + { + var traceParams = Mock.Of(); + Mock.Get(traceParams).Setup(p => p.Sampler).Returns(Samplers.AlwaysSample); + Mock.Get(traceConfig).Setup(c => c.ActiveTraceParams).Returns(traceParams); + + var span = tracer.SpanBuilder("foo").StartSpan(); + using (tracer.WithSpan(span)) + { + Assert.Same(span, tracer.CurrentSpan); + } + Assert.Same(BlankSpan.Instance, tracer.CurrentSpan); + } + + [Fact] + public void WithSpanNull() + { + Assert.Throws(() => tracer.WithSpan(null)); + } + + [Fact] + public void GetTextFormat() + { + Assert.NotNull(tracer.TextFormat); + } + + [Fact] + public void GetBinaryFormat() + { + Assert.NotNull(tracer.BinaryFormat); } + + // TODO test for sampler } } diff --git a/test/OpenTelemetry.Tests/Impl/Trace/TracingTest.cs b/test/OpenTelemetry.Tests/Impl/Trace/TracingTest.cs index 2b9a10ebb9e..6b997344b22 100644 --- a/test/OpenTelemetry.Tests/Impl/Trace/TracingTest.cs +++ b/test/OpenTelemetry.Tests/Impl/Trace/TracingTest.cs @@ -58,7 +58,7 @@ public class TracingTest [Fact(Skip = "need to fix the way tracer being instantiated")] public void DefaultTracer() { - Assert.Same(Tracer.NoopTracer, Tracing.Tracer); + Assert.Same(NoopTracer.Instance, Tracing.Tracer); } [Fact(Skip = "need to fix the way tracer being instantiated")]