Last active
April 12, 2019 13:25
-
-
Save jabrown85/82baf795fc3853266118996fbd30dd50 to your computer and use it in GitHub Desktop.
A basic implementation of sentry for aspnet core using existing RavenSharp (full .NET framework required)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Collections.Specialized; | |
using System.Dynamic; | |
using System.IO; | |
using System.Linq; | |
using System.Text; | |
using Microsoft.AspNetCore.Http; | |
using Microsoft.Extensions.Primitives; | |
using SharpRaven.Data; | |
using SharpRaven.Utilities; | |
namespace Project.Logging | |
{ | |
public class AspNetCoreSentryRequestFactory : ISentryRequestFactory | |
{ | |
public AspNetCoreSentryRequestFactory(HttpContext httpContext) | |
{ | |
HttpContext = httpContext; | |
} | |
private HttpContext HttpContext { get; } | |
public ISentryRequest Create() | |
{ | |
var request = new SentryRequest | |
{ | |
Url = HttpContext.Request.Path.ToString(), | |
Method = HttpContext.Request.Method, | |
Environment = new Dictionary<string, string>(), // NOTE: we did not want or need this | |
Headers = Convert(HttpContext.Request.Headers), | |
Cookies = HttpContext.Request.Cookies.ToDictionary(x => x.Key, x => x.Value), | |
Data = BodyConvert(), | |
QueryString = HttpContext.Request.QueryString.ToString(), | |
}; | |
return request; | |
} | |
private static IDictionary<string, string> Convert(IEnumerable<KeyValuePair<string, StringValues>> collection) | |
{ | |
return collection.ToDictionary(x => x.Key, x => string.Join(" ", x.Value.ToArray())); | |
} | |
private object BodyConvert() | |
{ | |
try | |
{ | |
dynamic wrapper = new ExpandoObject(); | |
wrapper.Request = new DynamicHttpContextRequest(HttpContext); | |
return HttpRequestBodyConverter.Convert(wrapper); | |
} | |
catch (Exception exception) | |
{ | |
SystemUtil.WriteError(exception); | |
} | |
return null; | |
} | |
/// <summary> | |
/// This code is mocking the HttpContext so that it can look like the original System.Web HttpContext that Sentry is still expecting, even though they | |
/// code against a dynamic, which is why this whole thing can work in the first place. | |
/// | |
/// We've only implemented the properties that are expected today. | |
/// </summary> | |
public class DynamicHttpContextRequest | |
{ | |
private readonly HttpContext _context; | |
private readonly MemoryStream _stream; | |
public DynamicHttpContextRequest(HttpContext context) | |
{ | |
_context = context; | |
if (_context.Request.Body == null) return; | |
using (var bodyReader = new StreamReader(_context.Request.Body)) | |
{ | |
var body = bodyReader.ReadToEndAsync().Result; | |
_stream = new MemoryStream(Encoding.UTF8.GetBytes(body)); | |
} | |
} | |
public string ContentType => _context.Request.ContentType; | |
public NameValueCollection Form | |
{ | |
get | |
{ | |
var coll = new NameValueCollection(); | |
foreach (var x in _context.Request.Form) | |
{ | |
coll.Add(x.Key, x.Value); | |
} | |
return coll; | |
} | |
} | |
public Stream InputStream => _stream; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using Microsoft.AspNetCore.Builder; | |
using Microsoft.AspNetCore.Http; | |
using Microsoft.Extensions.Logging; | |
namespace Project.Logging | |
{ | |
public static class SentryExtensions | |
{ | |
public static IApplicationBuilder UseSentry(this IApplicationBuilder app) | |
{ | |
if (app == null) | |
throw new ArgumentNullException(nameof(app)); | |
return app.UseMiddleware<SentryMiddleware>(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Threading.Tasks; | |
using Microsoft.AspNetCore.Http; | |
using Microsoft.Extensions.Options; | |
using SharpRaven; | |
using SharpRaven.Data; | |
namespace Project.Logging | |
{ | |
public class SentryMiddleware | |
{ | |
private readonly RequestDelegate _next; | |
private readonly SentryOptions _options; | |
public SentryMiddleware( | |
RequestDelegate next, | |
IOptions<SentryOptions> options) | |
{ | |
_next = next; | |
_options = options.Value; | |
} | |
public async Task Invoke(HttpContext context) | |
{ | |
try | |
{ | |
await _next(context); | |
} | |
catch (Exception ex) | |
{ | |
if (!string.IsNullOrWhiteSpace(_options.Dsn)) | |
{ | |
try | |
{ | |
var sentry = new RavenClient( | |
_options.Dsn, | |
sentryRequestFactory: new AspNetCoreSentryRequestFactory(context)); | |
await sentry.CaptureAsync(new SentryEvent(ex)); | |
} | |
catch (Exception sentryEx) | |
{ | |
throw new Exception($"Logging to sentry failed, {sentryEx}", ex); | |
} | |
} | |
throw; | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Project.Logging | |
{ | |
public class SentryOptions | |
{ | |
public string Dsn { get; set; } | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public Configure(IApplicationBuilder app) { | |
// ...snip... | |
app.UseSentry(); | |
// ...snip... | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment