Skip to content

Commit

Permalink
add an exception handler (#70)
Browse files Browse the repository at this point in the history
  • Loading branch information
austinlparker authored Apr 22, 2019
1 parent dbc6845 commit bfd0bb8
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 10 deletions.
21 changes: 21 additions & 0 deletions src/LightStep/Collector/ILightStepHttpClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System.Threading.Tasks;

namespace LightStep.Collector
{
public interface ILightStepHttpClient
{
/// <summary>
/// Send a report of spans to the LightStep Satellite.
/// </summary>
/// <param name="report">An <see cref="ReportRequest" /></param>
/// <returns>A <see cref="ReportResponse" />. This is usually not very interesting.</returns>
Task<ReportResponse> SendReport(ReportRequest report);

/// <summary>
/// Translate SpanData to a protobuf ReportRequest for sending to the Satellite.
/// </summary>
/// <param name="spans">An enumerable of <see cref="SpanData" /></param>
/// <returns>A <see cref="ReportRequest" /></returns>
ReportRequest Translate(ISpanRecorder spanBuffer);
}
}
6 changes: 3 additions & 3 deletions src/LightStep/Collector/LightStepHttpClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace LightStep.Collector
/// <summary>
/// Contains methods to communicate to a LightStep Satellite via Proto over HTTP.
/// </summary>
public class LightStepHttpClient
public class LightStepHttpClient : ILightStepHttpClient
{
private readonly Options _options;
private HttpClient _client;
Expand Down Expand Up @@ -69,7 +69,7 @@ internal HttpRequestMessage BuildRequest(ReportRequest report)
/// <param name="report">An <see cref="ReportRequest" /></param>
/// <returns>A <see cref="ReportResponse" />. This is usually not very interesting.</returns>
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
internal async Task<ReportResponse> SendReport(ReportRequest report)
public async Task<ReportResponse> SendReport(ReportRequest report)
{
// force net45 to attempt tls12 first and fallback appropriately
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
Expand Down Expand Up @@ -116,7 +116,7 @@ internal async Task<ReportResponse> SendReport(ReportRequest report)
/// </summary>
/// <param name="spans">An enumerable of <see cref="SpanData" /></param>
/// <returns>A <see cref="ReportRequest" /></returns>
internal ReportRequest Translate(ISpanRecorder spanBuffer)
public ReportRequest Translate(ISpanRecorder spanBuffer)
{
_logger.Debug($"Serializing {spanBuffer.GetSpans().Count()} spans to proto.");
var timer = new Stopwatch();
Expand Down
12 changes: 12 additions & 0 deletions src/LightStep/Options.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ public class Options
/// </summary>
public Boolean EnableMetaEventLogging { get; internal set; }

public Action<Exception> ExceptionHandler { get; internal set; }
public Boolean ExceptionHandlerRegistered { get; internal set; }

public Options WithMetaEventLogging()
{
_logger.Debug("Enabling Meta Events");
Expand Down Expand Up @@ -139,6 +142,14 @@ public Options WithTransport(TransportOptions transport)
Transport = transport;
return this;
}

public Options WithExceptionHandler(Action<Exception> handler)
{
_logger.Debug($"Registering exception handler {handler}");
ExceptionHandler = handler;
ExceptionHandlerRegistered = true;
return this;
}

/// <summary>
/// Creates a new set of options for the LightStep tracer.
Expand All @@ -156,6 +167,7 @@ public Options(string token = "")
ReportMaxSpans = int.MaxValue;
Transport = TransportOptions.BinaryProto;
EnableMetaEventLogging = false;
ExceptionHandlerRegistered = false;
}

private IDictionary<string, object> MergeTags(IDictionary<string, object> input)
Expand Down
23 changes: 16 additions & 7 deletions src/LightStep/Tracer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public sealed class Tracer : ITracer
private readonly object _lock = new object();
internal readonly Options _options;
private readonly IPropagator _propagator;
private readonly LightStepHttpClient _httpClient;
private readonly ILightStepHttpClient _httpClient;
private ISpanRecorder _spanRecorder;
private readonly Timer _reportLoop;
private static readonly ILog _logger = LogProvider.GetCurrentClassLogger();
Expand All @@ -28,29 +28,34 @@ public sealed class Tracer : ITracer

/// <inheritdoc />
public Tracer(Options options) : this(new AsyncLocalScopeManager(), Propagators.TextMap, options,
new LightStepSpanRecorder())
new LightStepSpanRecorder(), null)
{
}

/// <inheritdoc />
public Tracer(Options options, ISpanRecorder spanRecorder) : this(new AsyncLocalScopeManager(),
Propagators.TextMap, options, spanRecorder)
Propagators.TextMap, options, spanRecorder, null)
{
}

/// <inheritdoc />
public Tracer(Options options, IScopeManager scopeManager) : this(scopeManager, Propagators.TextMap, options,
new LightStepSpanRecorder())
new LightStepSpanRecorder(), null)
{
}

/// <inheritdoc />
public Tracer(Options options, ISpanRecorder spanRecorder, IPropagator propagator) : this(
new AsyncLocalScopeManager(), propagator, options, spanRecorder)
new AsyncLocalScopeManager(), propagator, options, spanRecorder, null)
{
}

private Tracer(IScopeManager scopeManager, IPropagator propagator, Options options, ISpanRecorder spanRecorder)
public Tracer(Options options, ISpanRecorder spanRecorder, ILightStepHttpClient client) : this(
new AsyncLocalScopeManager(), Propagators.TextMap, options, spanRecorder, client)
{
}

private Tracer(IScopeManager scopeManager, IPropagator propagator, Options options, ISpanRecorder spanRecorder, ILightStepHttpClient client)
{
ScopeManager = scopeManager;
_spanRecorder = spanRecorder;
Expand All @@ -61,7 +66,7 @@ private Tracer(IScopeManager scopeManager, IPropagator propagator, Options optio
var protocol = _options.Satellite.UsePlaintext ? "http" : "https";
var url =
$"{protocol}://{_options.Satellite.SatelliteHost}:{_options.Satellite.SatellitePort}/{LightStepConstants.SatelliteReportPath}";
_httpClient = new LightStepHttpClient(url, _options);
_httpClient = client ?? new LightStepHttpClient(url, _options);
_logger.Debug($"Tracer is reporting to {url}.");
_reportLoop = new Timer(e => Flush(), null, TimeSpan.Zero, _options.ReportPeriod);
_firstReportHasRun = false;
Expand Down Expand Up @@ -182,6 +187,10 @@ public async void Flush()
{
_logger.Warn($"Adding {currentBuffer.GetSpans().Count()} spans to dropped span count (current total: {currentDroppedSpanCount})");
currentDroppedSpanCount += currentBuffer.GetSpans().Count();
if (this._options.ExceptionHandlerRegistered)
{
this._options.ExceptionHandler.Invoke(ex);
}
}
}

Expand Down
23 changes: 23 additions & 0 deletions test/LightStep.Tests/TracerTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using LightStep.Collector;
using Moq;
using OpenTracing.Propagation;
using Xunit;

Expand Down Expand Up @@ -105,5 +107,26 @@ public void TracerOptionsShouldLetYouOverrideTags()
Assert.Equal(LightStepConstants.TracerPlatformValue,
tracerOptions.Tags[LightStepConstants.TracerPlatformKey]);
}

[Fact]
public void TracerShouldTrapExceptions()
{
var x = false;
Action<Exception> eh = delegate { x = true; };
var satelliteOptions = new SatelliteOptions("localhost", 80, true);
var tracerOptions = new Options().WithSatellite(satelliteOptions).WithExceptionHandler(eh.Invoke);
var recorder = new SimpleMockRecorder();
var mockClient = new Mock<ILightStepHttpClient>();
mockClient.Setup(client => client.Translate(recorder)).Throws<OverflowException>();

var tracer = new Tracer(tracerOptions, recorder, mockClient.Object);

var span = tracer.BuildSpan("test").Start();
span.Finish();

Assert.False(x);
tracer.Flush();
Assert.True(x);
}
}
}

0 comments on commit bfd0bb8

Please sign in to comment.