Display span information on Z page (#491)

* Classes scaffolding for zPages

Implemented Http Server to create HTML that displays span count using SimpleSpanProcessor

* incorporating review comments

- made ContentType const in zpages stats builder
- modified return statements in zpages exporter
- removed implementation folder from ZPages.csproj
- changed default uri for zpages test application
- changed data type of spanCount to long, and doing Interlocked.Increment when span starts

* fixing minor error

* Delete Exporters.csproj

Fix for https://github.com/open-telemetry/opentelemetry-dotnet/issues/480

* Delete Exporters.csproj

Fix for https://github.com/open-telemetry/opentelemetry-dotnet/issues/480

* displaying span status on zpages

* Adding Span Error Count and fixing build failure

* Adding Span Latency to zpages http server

* Adding class for storing span information

* Adding methods for calculating latency, count and error count values in last hour and last minutes

* Building HTML for zpage and adding timer for calculating metrics

* Implementation changes

- Added ZPages Span Processor
- Changed the logic for metrics calculation

* Update src/OpenTelemetry.Exporter.ZPages/Implementation/ZPagesStatsBuilder.cs

Co-authored-by: Sergey Kanzhelev <S.Kanzhelev@live.com>

* Incoroporating Review Comments

Co-authored-by: Sergey Kanzhelev <S.Kanzhelev@live.com>
Co-authored-by: Cijo Thomas <cithomas@microsoft.com>
This commit is contained in:
HarnidhK 2020-06-01 23:15:41 -07:00 committed by GitHub
parent 4ed65d3ddd
commit 0867c66a0f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 469 additions and 27 deletions

View File

@ -17,6 +17,7 @@
using System;
using System.Threading;
using OpenTelemetry.Exporter.ZPages;
using OpenTelemetry.Exporter.ZPages.Implementation;
using OpenTelemetry.Trace;
using OpenTelemetry.Trace.Configuration;
using OpenTelemetry.Trace.Export;
@ -29,28 +30,49 @@ namespace Samples
{
var zpagesOptions = new ZPagesExporterOptions() { Url = "http://localhost:7284/rpcz/" };
var zpagesExporter = new ZPagesExporter(zpagesOptions);
var spanProcessor = new SimpleSpanProcessor(zpagesExporter);
var spanProcessor = new ZPagesSpanProcessor(zpagesExporter);
ZPagesSpans.RetentionTime = 3600000;
var httpServer = new ZPagesExporterStatsHttpServer(zpagesExporter, spanProcessor);
// Start the server
httpServer.Start();
// Configure exporter
using var tracerFactory = TracerFactory.Create(builder => builder
using (var tracerFactory = TracerFactory.Create(builder => builder
.AddProcessorPipeline(b => b
.SetExporter(zpagesExporter)
.SetExportingProcessor(e => spanProcessor)));
var tracer = tracerFactory.GetTracer("zpages-test");
while (true)
.SetExportingProcessor(e => spanProcessor))))
{
// Create a scoped span. It will end automatically when using statement ends
using (tracer.WithSpan(tracer.StartSpan("Main")))
{
Console.WriteLine("Starting Span");
}
var tracer = tracerFactory.GetTracer("zpages-test");
Thread.Sleep(500);
while (true)
{
// Create a scoped span.
TelemetrySpan telemetrySpan = tracer.StartSpan("Main");
telemetrySpan.Status = Status.Unavailable;
using (tracer.WithSpan(telemetrySpan))
{
Console.WriteLine("Starting Span");
}
Thread.Sleep(3000);
telemetrySpan.End();
// Create a scoped span.
TelemetrySpan telemetrySpan2 = tracer.StartSpan("TestSpan");
telemetrySpan2.Status = Status.Ok;
using (tracer.WithSpan(telemetrySpan2))
{
Console.WriteLine("Starting Span2");
}
Thread.Sleep(5000);
telemetrySpan2.End();
}
}
}
}

View File

@ -0,0 +1,98 @@
// <copyright file="ZPagesSpanInformation.cs" company="OpenTelemetry Authors">
// Copyright The 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.
// </copyright>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using OpenTelemetry.Trace.Export;
namespace OpenTelemetry.Exporter.ZPages.Implementation
{
/// <summary>
/// Stores the span information aggregated according to span name.
/// </summary>
public class ZPagesSpanInformation
{
/// <summary>
/// Initializes a new instance of the <see cref="ZPagesSpanInformation"/> class.
/// </summary>
public ZPagesSpanInformation()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ZPagesSpanInformation"/> class when span data is provided.
/// </summary>
/// <param name="spanData">Input span data to be used for initialization.</param>
public ZPagesSpanInformation(SpanData spanData)
{
this.Name = spanData.Name;
this.Count = 1;
this.EndedCount = 0;
this.LastUpdated = new DateTimeOffset(DateTime.Now).ToUnixTimeMilliseconds();
this.TotalLatency = 0;
this.AvgLatencyTotal = 0;
this.ErrorCount = 0;
}
/// <summary>
/// Gets or sets the name of the span.
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets or sets the total count of the span.
/// </summary>
public long Count { get; set; }
/// <summary>
/// Gets or sets the total count of the ended span.
/// </summary>
public long EndedCount { get; set; }
/// <summary>
/// Gets or sets the total error count of the span.
/// </summary>
public long ErrorCount { get; set; }
/// <summary>
/// Gets or sets the total average latency of the span.
/// </summary>
public long AvgLatencyTotal { get; set; }
/// <summary>
/// Gets or sets the total latency of all spans.
/// </summary>
public long TotalLatency { get; set; }
/// <summary>
/// Gets or sets the last updated timestamp.
/// </summary>
public long LastUpdated { get; set; }
/// <summary>
/// Calculates and returns the total average latency.
/// </summary>
/// <returns>Total average latency.</returns>
public long GetTotalAverageLatency()
{
this.AvgLatencyTotal = this.TotalLatency / this.EndedCount;
this.LastUpdated = new DateTimeOffset(DateTime.Now).ToUnixTimeMilliseconds();
return this.AvgLatencyTotal;
}
}
}

View File

@ -0,0 +1,123 @@
// <copyright file="ZPagesSpans.cs" company="OpenTelemetry Authors">
// Copyright The 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.
// </copyright>
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Timers;
namespace OpenTelemetry.Exporter.ZPages.Implementation
{
/// <summary>
/// Implements the ZPages Span Queue which stores all the required span information.
/// </summary>
public static class ZPagesSpans
{
private static long startTime;
/// <summary>
/// Initializes static members of the <see cref="ZPagesSpans"/> class.
/// </summary>
static ZPagesSpans()
{
ZQueue = new LinkedList<Dictionary<string, ZPagesSpanInformation>>();
ProcessingSpanList = new Dictionary<string, long>();
CurrentMinuteSpanList = new ConcurrentDictionary<string, ZPagesSpanInformation>();
CurrentHourSpanList = new ConcurrentDictionary<string, ZPagesSpanInformation>();
TotalSpanCount = new Dictionary<string, long>();
TotalEndedSpanCount = new Dictionary<string, long>();
TotalSpanErrorCount = new Dictionary<string, long>();
TotalSpanLatency = new Dictionary<string, long>();
startTime = DateTimeOffset.Now.ToUnixTimeMilliseconds();
}
/// <summary>
/// Gets or sets ZQueue which stores the minute-wise span information.
/// </summary>
public static LinkedList<Dictionary<string, ZPagesSpanInformation>> ZQueue { get; set; }
/// <summary>
/// Gets or sets the current minute span information list.
/// </summary>
public static ConcurrentDictionary<string, ZPagesSpanInformation> CurrentMinuteSpanList { get; set; }
/// <summary>
/// Gets or sets the current hour span information list.
/// </summary>
public static ConcurrentDictionary<string, ZPagesSpanInformation> CurrentHourSpanList { get; set; }
/// <summary>
/// Gets or sets the processing span information list. This holds the names of the spans which have not ended yet, along with the active count.
/// </summary>
public static Dictionary<string, long> ProcessingSpanList { get; set; }
/// <summary>
/// Gets or sets the count of spans name-wise.
/// </summary>
public static Dictionary<string, long> TotalSpanCount { get; set; }
/// <summary>
/// Gets or sets the count of ended spans name-wise.
/// </summary>
public static Dictionary<string, long> TotalEndedSpanCount { get; set; }
/// <summary>
/// Gets or sets the count of span errors according to span name.
/// </summary>
public static Dictionary<string, long> TotalSpanErrorCount { get; set; }
/// <summary>
/// Gets or sets the total latency of spans name-wise.
/// </summary>
public static Dictionary<string, long> TotalSpanLatency { get; set; }
/// <summary>
/// Gets or sets the retention time (in milliseconds) for the metrics.
/// </summary>
public static long RetentionTime { get; set; }
/// <summary>
/// Triggers Calculations every minute.
/// </summary>
/// <param name="source">Source.</param>
/// <param name="e">Event Arguments.</param>
public static void PurgeCurrentMinuteData(object source, ElapsedEventArgs e)
{
// Enqueue the last minute's span information list to ZQueue
ZQueue.AddFirst(new Dictionary<string, ZPagesSpanInformation>(CurrentMinuteSpanList));
// Clear the current minute span list to start recording new spans only
CurrentMinuteSpanList.Clear();
// Remove the stale span information which is at the end of the list
if (DateTimeOffset.Now.ToUnixTimeMilliseconds() - startTime >= RetentionTime)
{
ZQueue.RemoveLast();
}
}
/// <summary>
/// Triggers Calculations every hour.
/// </summary>
/// <param name="source">Source.</param>
/// <param name="e">Event Arguments.</param>
public static void PurgeCurrentHourData(object source, ElapsedEventArgs e)
{
// Clear the last hour's span information list
CurrentHourSpanList.Clear();
}
}
}

View File

@ -18,6 +18,6 @@ namespace OpenTelemetry.Exporter.ZPages.Implementation
{
internal class ZPagesStatsBuilder
{
public const string ContentType = "text/plain; version = 0.0.4";
public const string ContentType = "text/html";
}
}

View File

@ -13,10 +13,16 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using OpenTelemetry.Exporter.ZPages.Implementation;
using OpenTelemetry.Trace.Export;
using Timer = System.Timers.Timer;
namespace OpenTelemetry.Exporter.ZPages
{
@ -26,6 +32,8 @@ namespace OpenTelemetry.Exporter.ZPages
public class ZPagesExporter : SpanExporter
{
internal readonly ZPagesExporterOptions Options;
private Timer minuteTimer;
private Timer hourTimer;
/// <summary>
/// Initializes a new instance of the <see cref="ZPagesExporter"/> class.
@ -34,11 +42,22 @@ namespace OpenTelemetry.Exporter.ZPages
public ZPagesExporter(ZPagesExporterOptions options)
{
this.Options = options;
// Create a timer with one minute interval
this.minuteTimer = new Timer(60000);
this.minuteTimer.Elapsed += new ElapsedEventHandler(ZPagesSpans.PurgeCurrentMinuteData);
this.minuteTimer.Enabled = true;
// Create a timer with one hour interval
this.hourTimer = new Timer(3600000);
this.hourTimer.Elapsed += new ElapsedEventHandler(ZPagesSpans.PurgeCurrentHourData);
this.hourTimer.Enabled = true;
}
/// <inheritdoc />
public override Task<ExportResult> ExportAsync(IEnumerable<SpanData> batch, CancellationToken cancellationToken)
{
var spanDatas = batch as SpanData[] ?? batch.ToArray();
return Task.FromResult(ExportResult.Success);
}

View File

@ -15,8 +15,11 @@
// </copyright>
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using OpenTelemetry.Exporter.ZPages.Implementation;
@ -30,7 +33,7 @@ namespace OpenTelemetry.Exporter.ZPages
public class ZPagesExporterStatsHttpServer : IDisposable
{
private readonly ZPagesExporter exporter;
private readonly SimpleSpanProcessor spanProcessor;
private readonly ZPagesSpanProcessor spanProcessor;
private readonly HttpListener httpListener = new HttpListener();
private readonly object lck = new object();
@ -42,7 +45,7 @@ namespace OpenTelemetry.Exporter.ZPages
/// </summary>
/// <param name="exporter">The <see cref="ZPagesExporterStatsHttpServer"/> instance.</param>
/// <param name="spanProcessor">The <see cref="SimpleSpanProcessor"/> instance.</param>
public ZPagesExporterStatsHttpServer(ZPagesExporter exporter, SimpleSpanProcessor spanProcessor)
public ZPagesExporterStatsHttpServer(ZPagesExporter exporter, ZPagesSpanProcessor spanProcessor)
{
this.exporter = exporter;
this.spanProcessor = spanProcessor;
@ -52,7 +55,7 @@ namespace OpenTelemetry.Exporter.ZPages
/// <summary>
/// Start exporter.
/// </summary>
/// <param name="token">An optional <see cref="CancellationToken"/> that can be used to stop the htto server.</param>
/// <param name="token">An optional <see cref="CancellationToken"/> that can be used to stop the http server.</param>
public void Start(CancellationToken token = default)
{
lock (this.lck)
@ -108,7 +111,7 @@ namespace OpenTelemetry.Exporter.ZPages
{
while (!this.tokenSource.IsCancellationRequested)
{
var ctxTask = this.httpListener.GetContextAsync();
Task<HttpListenerContext> ctxTask = this.httpListener.GetContextAsync();
ctxTask.Wait(this.tokenSource.Token);
var ctx = ctxTask.Result;
@ -116,9 +119,62 @@ namespace OpenTelemetry.Exporter.ZPages
ctx.Response.StatusCode = 200;
ctx.Response.ContentType = ZPagesStatsBuilder.ContentType;
using var output = ctx.Response.OutputStream;
using var writer = new StreamWriter(output);
writer.WriteLine("Span Count : " + this.spanProcessor.GetSpanCount());
using (Stream output = ctx.Response.OutputStream)
{
using (var writer = new StreamWriter(output))
{
writer.WriteLine("<!DOCTYPE html>");
writer.WriteLine("<html><head><title>RPC Stats</title>" +
"<meta charset=\"utf-8\">" +
"<link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css\">" +
"<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js\"></script>" +
"<script src=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js\"></script>" +
"</head>");
writer.WriteLine("<body><div class=\"col-sm-1\"></div><div class=\"container col-sm-10\"><div class=\"jumbotron table-responsive\"><h1>RPC Stats</h2>" +
"<table class=\"table table-bordered table-hover table-striped\">" +
"<thead><tr><th>Span Name</th><th>Total Count</th><th>Count in last minute</th><th>Count in last hour</th><th>Average Latency (ms)</th>" +
"<th>Average Latency in last minute (ms)</th><th>Average Latency in last hour (ms)</th><th>Total Errors</th><th>Errors in last minute</th><th>Errors in last minute</th><th>Last Updated</th></tr></thead>" +
"<tbody>");
ConcurrentDictionary<string, ZPagesSpanInformation> currentHourSpanList = ZPagesSpans.CurrentHourSpanList;
ConcurrentDictionary<string, ZPagesSpanInformation> currentMinuteSpanList = ZPagesSpans.CurrentMinuteSpanList;
// Put span information in each row of the table
foreach (var spanName in currentHourSpanList.Keys)
{
ZPagesSpanInformation minuteSpanInformation = new ZPagesSpanInformation();
ZPagesSpanInformation hourSpanInformation = new ZPagesSpanInformation();
long countInLastMinute = 0;
long countInLastHour = 0;
long averageLatencyInLastMinute = 0;
long averageLatencyInLastHour = 0;
long errorCountInLastMinute = 0;
long errorCountInLastHour = 0;
if (currentMinuteSpanList.ContainsKey(spanName))
{
currentMinuteSpanList.TryGetValue(spanName, out minuteSpanInformation);
countInLastMinute = minuteSpanInformation.EndedCount + ZPagesSpans.ProcessingSpanList[spanName];
averageLatencyInLastMinute = minuteSpanInformation.AvgLatencyTotal;
errorCountInLastMinute = minuteSpanInformation.ErrorCount;
}
currentHourSpanList.TryGetValue(spanName, out hourSpanInformation);
countInLastHour = hourSpanInformation.EndedCount + ZPagesSpans.ProcessingSpanList[spanName];
averageLatencyInLastHour = hourSpanInformation.AvgLatencyTotal;
errorCountInLastHour = hourSpanInformation.ErrorCount;
long totalAverageLatency = ZPagesSpans.TotalSpanLatency[spanName] / ZPagesSpans.TotalEndedSpanCount[spanName];
writer.WriteLine("<tr><td>" + hourSpanInformation.Name + "</td><td>" + ZPagesSpans.TotalSpanCount[spanName] + "</td><td>" + countInLastMinute + "</td><td>" + countInLastHour + "</td>" +
"<td>" + totalAverageLatency + "</td><td>" + averageLatencyInLastMinute + "</td><td>" + averageLatencyInLastHour + "</td>" +
"<td>" + ZPagesSpans.TotalSpanErrorCount[spanName] + "</td><td>" + errorCountInLastMinute + "</td><td>" + errorCountInLastHour + "</td><td>" + DateTimeOffset.FromUnixTimeMilliseconds(hourSpanInformation.LastUpdated) + " GMT" + "</td></tr>");
}
writer.WriteLine("</tbody></table>");
writer.WriteLine("</div></div></body></html>");
}
}
}
}
catch (OperationCanceledException)

View File

@ -0,0 +1,129 @@
// <copyright file="ZPagesSpanProcessor.cs" company="OpenTelemetry Authors">
// Copyright The 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.
// </copyright>
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using OpenTelemetry.Exporter.ZPages.Implementation;
using OpenTelemetry.Trace.Export;
using Timer = System.Timers.Timer;
namespace OpenTelemetry.Exporter.ZPages
{
/// <summary>
/// Implements the zpages span processor that exports spans in OnEnd call without batching.
/// </summary>
public class ZPagesSpanProcessor : SpanProcessor
{
private readonly ZPagesExporter exporter;
/// <summary>
/// Initializes a new instance of the <see cref="ZPagesSpanProcessor"/> class.
/// </summary>
/// <param name="exporter">Zpage Span processor instance.</param>
public ZPagesSpanProcessor(ZPagesExporter exporter)
{
this.exporter = exporter;
}
/// <inheritdoc />
public override void OnStart(SpanData span)
{
if (!ZPagesSpans.ProcessingSpanList.ContainsKey(span.Name))
{
// If the span name is not in the processing span list, add it to the span list, the total count list, the ended count list and the error count list.
ZPagesSpans.ProcessingSpanList.Add(span.Name, 1);
ZPagesSpans.TotalSpanCount.Add(span.Name, 1);
ZPagesSpans.TotalEndedSpanCount.Add(span.Name, 0);
ZPagesSpans.TotalSpanErrorCount.Add(span.Name, 0);
ZPagesSpans.TotalSpanLatency.Add(span.Name, 0);
}
else
{
// If the span name already exists, then increment the numbers in processing list as well as the total count list.
ZPagesSpans.ProcessingSpanList.TryGetValue(span.Name, out var activeCount);
ZPagesSpans.ProcessingSpanList[span.Name] = activeCount + 1;
ZPagesSpans.TotalSpanCount.TryGetValue(span.Name, out var totalCount);
ZPagesSpans.TotalSpanCount[span.Name] = totalCount + 1;
}
}
/// <inheritdoc />
public override void OnEnd(SpanData span)
{
try
{
// do not await, just start export
// it can still throw in synchronous part
_ = this.exporter.ExportAsync(new[] { span }, CancellationToken.None);
// If the span name is not in the current minute list, add it to the span list.
if (!ZPagesSpans.CurrentMinuteSpanList.ContainsKey(span.Name))
{
ZPagesSpans.CurrentMinuteSpanList.TryAdd(span.Name, new ZPagesSpanInformation(span));
}
// If the span name is not in the current hour list, add it to the span list.
if (!ZPagesSpans.CurrentHourSpanList.ContainsKey(span.Name))
{
ZPagesSpans.CurrentHourSpanList.TryAdd(span.Name, new ZPagesSpanInformation(span));
}
ZPagesSpans.CurrentMinuteSpanList.TryGetValue(span.Name, out var minuteSpanInformation);
ZPagesSpans.CurrentHourSpanList.TryGetValue(span.Name, out var hourSpanInformation);
ZPagesSpans.ProcessingSpanList.TryGetValue(span.Name, out var activeCount);
// Decrement the active span count in processing list, Increment the count of ended spans and calculate the average latency values for one minute and one hour.
ZPagesSpans.ProcessingSpanList[span.Name] = activeCount - 1;
minuteSpanInformation.EndedCount++;
hourSpanInformation.EndedCount++;
minuteSpanInformation.TotalLatency += span.EndTimestamp.ToUnixTimeMilliseconds() - span.StartTimestamp.ToUnixTimeMilliseconds();
hourSpanInformation.TotalLatency += span.EndTimestamp.ToUnixTimeMilliseconds() - span.StartTimestamp.ToUnixTimeMilliseconds();
ZPagesSpans.TotalSpanLatency[span.Name] += span.EndTimestamp.ToUnixTimeMilliseconds() - span.StartTimestamp.ToUnixTimeMilliseconds();
minuteSpanInformation.GetTotalAverageLatency();
hourSpanInformation.GetTotalAverageLatency();
ZPagesSpans.TotalEndedSpanCount.TryGetValue(span.Name, out var endedCount);
ZPagesSpans.TotalEndedSpanCount[span.Name] = endedCount + 1;
// Increment the error count, if it applies in all applicable lists.
if (!span.Status.IsOk)
{
minuteSpanInformation.ErrorCount++;
hourSpanInformation.ErrorCount++;
ZPagesSpans.TotalSpanErrorCount.TryGetValue(span.Name, out var errorCount);
ZPagesSpans.TotalSpanErrorCount[span.Name] = errorCount + 1;
}
// Set the last updated timestamp.
minuteSpanInformation.LastUpdated = new DateTimeOffset(DateTime.Now).ToUnixTimeMilliseconds();
hourSpanInformation.LastUpdated = new DateTimeOffset(DateTime.Now).ToUnixTimeMilliseconds();
}
catch (Exception exception)
{
// Log.SpanProcessorException("OnEnd", ex);
Console.Write("OnEnd", exception);
}
}
/// <inheritdoc />
public override Task ShutdownAsync(CancellationToken cancellationToken)
{
throw new System.NotImplementedException();
}
}
}

View File

@ -14,6 +14,8 @@
// limitations under the License.
// </copyright>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using OpenTelemetry.Internal;
@ -27,7 +29,6 @@ namespace OpenTelemetry.Trace.Export
{
private readonly SpanExporter exporter;
private bool disposed = false;
private long spanCount = 0;
/// <summary>
/// Initializes a new instance of the <see cref="SimpleSpanProcessor"/> class.
@ -38,15 +39,9 @@ namespace OpenTelemetry.Trace.Export
this.exporter = exporter ?? throw new ArgumentNullException(nameof(exporter));
}
public long GetSpanCount()
{
return this.spanCount;
}
/// <inheritdoc />
public override void OnStart(SpanData span)
{
Interlocked.Increment(ref this.spanCount);
}
/// <inheritdoc />