1
0
mirror of https://github.com/ncblakely/GiantsTools synced 2024-11-23 22:55:37 +01:00

Mirror minidumps to Sentry for easier analysis.

This commit is contained in:
Nick Blakely 2020-09-01 11:04:22 -07:00
parent 4877479528
commit 1f4d4e846c
5 changed files with 78 additions and 8 deletions

View File

@ -1,5 +1,7 @@
namespace Giants.Services namespace Giants.Services
{ {
using System;
using System.Net.Http.Headers;
using Giants.Services.Core; using Giants.Services.Core;
using Giants.Services.Services; using Giants.Services.Services;
using Giants.Services.Store; using Giants.Services.Store;
@ -22,6 +24,14 @@
services.AddHostedService<InitializerService>(); services.AddHostedService<InitializerService>();
services.AddHostedService<ServerRegistryCleanupService>(); services.AddHostedService<ServerRegistryCleanupService>();
services.AddHttpClient("Sentry", c =>
{
c.BaseAddress = new Uri(configuration["SentryBaseUri"]);
string sentryAuthenticationToken = configuration["SentryAuthenticationToken"];
c.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", sentryAuthenticationToken);
});
} }
} }
} }

View File

@ -8,11 +8,13 @@
<PackageReference Include="AutoMapper" Version="10.0.0" /> <PackageReference Include="AutoMapper" Version="10.0.0" />
<PackageReference Include="Azure.Storage.Blobs" Version="12.5.1" /> <PackageReference Include="Azure.Storage.Blobs" Version="12.5.1" />
<PackageReference Include="Microsoft.Azure.Cosmos" Version="3.12.0" /> <PackageReference Include="Microsoft.Azure.Cosmos" Version="3.12.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="3.1.6" /> <PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="3.1.7" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="3.1.6" /> <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="3.1.7" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="3.1.6" /> <PackageReference Include="Microsoft.Extensions.Configuration" Version="3.1.7" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.6" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.7" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.6" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.7" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.7" />
<PackageReference Include="Microsoft.Extensions.Http" Version="3.1.7" />
<PackageReference Include="System.Runtime.Caching" Version="4.7.0" /> <PackageReference Include="System.Runtime.Caching" Version="4.7.0" />
</ItemGroup> </ItemGroup>

View File

@ -2,6 +2,9 @@
{ {
using System; using System;
using System.IO; using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using Azure.Storage.Blobs; using Azure.Storage.Blobs;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
@ -12,18 +15,53 @@
private readonly BlobServiceClient blobServiceClient; private readonly BlobServiceClient blobServiceClient;
private readonly IConfiguration configuration; private readonly IConfiguration configuration;
private readonly ILogger<CrashReportService> logger; private readonly ILogger<CrashReportService> logger;
private readonly IHttpClientFactory clientFactory;
private const string SentryMinidumpUploadFileKey = "upload_file_minidump";
public CrashReportService( public CrashReportService(
IConfiguration configuration, IConfiguration configuration,
ILogger<CrashReportService> logger) ILogger<CrashReportService> logger,
IHttpClientFactory clientFactory)
{ {
this.configuration = configuration; this.configuration = configuration;
this.logger = logger; this.logger = logger;
this.clientFactory = clientFactory;
string blobConnectionString = configuration["BlobConnectionString"]; string blobConnectionString = configuration["BlobConnectionString"];
this.blobServiceClient = new BlobServiceClient(blobConnectionString); this.blobServiceClient = new BlobServiceClient(blobConnectionString);
} }
public async Task UploadMinidumpToSentry(string fileName, Stream stream)
{
string minidumpUri = this.configuration["SentryMinidumpUri"];
if (string.IsNullOrEmpty(minidumpUri))
{
throw new InvalidOperationException("Minidump URI is not defined.");
}
var httpClient = this.clientFactory.CreateClient("Sentry");
using var zipArchive = new ZipArchive(stream);
var zipEntry = zipArchive.Entries.FirstOrDefault(e => e.Name == "crashdump.dmp");
if (zipEntry == null)
{
throw new InvalidOperationException("No crash dump found in archive.");
}
using var dumpStream = zipEntry.Open();
using var formData = new MultipartFormDataContent
{
{ new StreamContent(dumpStream), SentryMinidumpUploadFileKey, fileName }
};
var response = await httpClient.PostAsync(minidumpUri, formData).ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
{
throw new InvalidOperationException();
}
}
public async Task ProcessReport(string fileName, string senderIpAddress, Stream stream) public async Task ProcessReport(string fileName, string senderIpAddress, Stream stream)
{ {
this.logger.LogInformation("Processing crash report file {FileName} from {IP}", fileName, senderIpAddress); this.logger.LogInformation("Processing crash report file {FileName} from {IP}", fileName, senderIpAddress);

View File

@ -5,6 +5,7 @@
public interface ICrashReportService public interface ICrashReportService
{ {
Task UploadMinidumpToSentry(string fileName, Stream stream);
Task ProcessReport(string fileName, string senderIpAddress, Stream stream); Task ProcessReport(string fileName, string senderIpAddress, Stream stream);
} }
} }

View File

@ -8,6 +8,8 @@
using Giants.Services.Services; using Giants.Services.Services;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
[ApiController] [ApiController]
[Route("api/[controller]")] [Route("api/[controller]")]
@ -15,15 +17,20 @@
{ {
private readonly ICrashReportService crashReportService; private readonly ICrashReportService crashReportService;
private readonly IHttpContextAccessor httpContextAccessor; private readonly IHttpContextAccessor httpContextAccessor;
private readonly ILogger<CrashReportsController> logger;
private readonly IConfiguration configuration;
private const long MaximumSizeInBytes = 5242880; // 5MB private const long MaximumSizeInBytes = 5242880; // 5MB
public CrashReportsController( public CrashReportsController(
ICrashReportService crashReportService, ICrashReportService crashReportService,
IHttpContextAccessor httpContextAccessor) IHttpContextAccessor httpContextAccessor,
ILogger<CrashReportsController> logger,
IConfiguration configuration)
{ {
this.crashReportService = crashReportService; this.crashReportService = crashReportService;
this.httpContextAccessor = httpContextAccessor; this.httpContextAccessor = httpContextAccessor;
this.logger = logger;
this.configuration = configuration;
} }
[HttpPost] [HttpPost]
@ -36,6 +43,18 @@
{ {
await this.crashReportService.ProcessReport(file.FileName, this.GetRequestIpAddress(), stream).ConfigureAwait(false); await this.crashReportService.ProcessReport(file.FileName, this.GetRequestIpAddress(), stream).ConfigureAwait(false);
} }
bool sentryEnabled = Convert.ToBoolean(this.configuration["SentryEnabled"]);
if (!sentryEnabled)
{
this.logger.LogInformation("Skipping Sentry upload; disabled.");
return;
}
using (var stream = file.OpenReadStream())
{
await this.crashReportService.UploadMinidumpToSentry(file.FileName, stream).ConfigureAwait(false);
}
} }
private void ValidateFiles(IEnumerable<IFormFile> formFiles) private void ValidateFiles(IEnumerable<IFormFile> formFiles)