Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
138 changes: 138 additions & 0 deletions src/Bugsnag/DefaultDelivery.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
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