Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Bugsnag/Bugsnag.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Net.Http" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<PackageReference Include="System.Collections.Specialized" Version="4.3.0" />
<PackageReference Include="System.Diagnostics.TraceSource" Version="4.3.0" />
<PackageReference Include="System.Diagnostics.StackTrace" Version="4.3.0" />
<PackageReference Include="System.Net.Requests" Version="4.3.0" />
<PackageReference Include="System.Runtime.Serialization.Primitives" Version="4.3.0" />
<PackageReference Include="System.Threading.Thread" Version="4.3.0" />
</ItemGroup>
Expand Down
4 changes: 2 additions & 2 deletions src/Bugsnag/Client.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ public Client(string apiKey) : this(new Configuration(apiKey))
/// Constructs a client with the default storage and delivery classes.
/// </summary>
/// <param name="configuration"></param>
public Client(IConfiguration configuration) : this(configuration, ThreadQueueDelivery.Instance, new Breadcrumbs(configuration), new SessionTracker(configuration))
public Client(IConfiguration configuration) : this(configuration, DefaultDelivery.Instance, new Breadcrumbs(configuration), new SessionTracker(configuration))
{

DefaultDelivery.Instance.Configure(configuration);
}

/// <summary>
Expand Down
135 changes: 135 additions & 0 deletions src/Bugsnag/DefaultDelivery.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
using Bugsnag.Payload;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Bugsnag
{
public class DefaultDelivery : IDelivery
{
private static DefaultDelivery instance = null;
private static readonly object instanceLock = new object();

private HttpClient _httpClient;
private readonly CancellationTokenSource _cancellationTokenSource;
private readonly Task _processingTask;
private readonly BlockingCollection<IPayload> _queue;

private DefaultDelivery()
{
_httpClient = new HttpClient();
_queue = new BlockingCollection<IPayload>(new ConcurrentQueue<IPayload>());
_cancellationTokenSource = new CancellationTokenSource();
_processingTask = Task.Run(() => ProcessQueueAsync(_cancellationTokenSource.Token));
}

public static DefaultDelivery Instance
{
get
{
lock (instanceLock)
{
if (instance == null)
{
instance = new DefaultDelivery();
}

return instance;
}
}
}

public void Configure(IConfiguration configuration)
{
if (configuration.Proxy != null)
{
_httpClient.Dispose();
_httpClient = new HttpClient(new HttpClientHandler { Proxy = configuration.Proxy });
}
}

public void Send(IPayload payload)
{
_queue.Add(payload);
}

internal void Stop()
{
Task.WaitAll(new[] { _processingTask }, TimeSpan.FromSeconds(5));
_cancellationTokenSource.Cancel();
_httpClient.Dispose();
_cancellationTokenSource.Dispose();
_queue.Dispose();
}

private async Task ProcessQueueAsync(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
IPayload payload = null;

try
{
// Take will block until an item is available or cancellation is requested
payload = _queue.Take(cancellationToken);
}
catch (OperationCanceledException)
{
// Exit gracefully when cancellation is requested
break;
}

if (payload != null)
{
await SendPayloadAsync(payload);
}
}
}

private async Task SendPayloadAsync(IPayload payload)
{
try
{
byte[] serializedPayload = payload.Serialize();
if (serializedPayload == null)
return;

using (var request = new HttpRequestMessage(HttpMethod.Post, payload.Endpoint))
{
request.Content = new ByteArrayContent(serializedPayload);
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");

// Add headers from payload
if (payload.Headers != null)
{
foreach (var header in payload.Headers)
{
request.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
}

// Add the Bugsnag-Sent-At header
request.Headers.Add("Bugsnag-Sent-At", DateTime.UtcNow.ToString("o", System.Globalization.CultureInfo.InvariantCulture));

// Send the request and log any failures
var response = await _httpClient.SendAsync(request);

if (!response.IsSuccessStatusCode) {
Trace.WriteLine($"Failed to send payload to Bugsnag - received status code {response.StatusCode}");
}
}
}
catch (System.Exception ex)
{
Trace.WriteLine($"Error sending payload to Bugsnag: {ex}");
}
}
}
}
2 changes: 0 additions & 2 deletions src/Bugsnag/IDelivery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ public interface IPayload
{
Uri Endpoint { get; }

IWebProxy Proxy { get; }

KeyValuePair<string, string>[] Headers { get; }

byte[] Serialize();
Expand Down
5 changes: 2 additions & 3 deletions src/Bugsnag/Payload/BatchedSessions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ public BatchedSessions(IConfiguration configuration, NotifierInfo notifier, App
{
_configuration = configuration;
Endpoint = configuration.SessionEndpoint;
Proxy = configuration.Proxy;

_headers = new KeyValuePair<string, string>[] {
new KeyValuePair<string, string>(Payload.Headers.ApiKeyHeader, configuration.ApiKey),
new KeyValuePair<string, string>(Payload.Headers.PayloadVersionHeader, "1.0")
};

this.AddToPayload("notifier", notifier);
this.AddToPayload("device", device);
this.AddToPayload("app", app);
Expand All @@ -32,8 +33,6 @@ public BatchedSessions(IConfiguration configuration, NotifierInfo notifier, App

public Uri Endpoint { get; set; }

public IWebProxy Proxy { get; set; }

public KeyValuePair<string, string>[] Headers => _headers;

public byte[] Serialize()
Expand Down
4 changes: 1 addition & 3 deletions src/Bugsnag/Payload/Report.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public Report(IConfiguration configuration, System.Exception exception, HandledS
{
_ignored = false;
Endpoint = configuration.Endpoint;
Proxy = configuration.Proxy;

_headers = new KeyValuePair<string, string>[] {
new KeyValuePair<string, string>(Payload.Headers.ApiKeyHeader, configuration.ApiKey),
new KeyValuePair<string, string>(Payload.Headers.PayloadVersionHeader, _payloadVersion),
Expand Down Expand Up @@ -87,8 +87,6 @@ public void Ignore()
/// </summary>
public Uri Endpoint { get; set; }

public IWebProxy Proxy { get; set; }

public KeyValuePair<string, string>[] Headers { get { return _headers; } }

public byte[] Serialize()
Expand Down
2 changes: 1 addition & 1 deletion src/Bugsnag/SessionsStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ private void SendSessions(object state)
foreach (var item in sessionData)
{
var payload = new BatchedSessions(item.Key, item.Value);
ThreadQueueDelivery.Instance.Send(payload);
DefaultDelivery.Instance.Send(payload);
}
}

Expand Down
173 changes: 0 additions & 173 deletions src/Bugsnag/ThreadQueueDelivery.cs

This file was deleted.

Loading