Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create CollectDump Collection Rule Action #824

Merged
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
1fd04e3
Currently a complete mess; the execute action for completing a dump m…
kkeirstead Aug 23, 2021
0d7c109
In the process of trying to get tests up and running; mostly just fig…
kkeirstead Aug 24, 2021
e43a2f4
Pulled in changes; in process of trying to get tests running for dump…
kkeirstead Aug 25, 2021
ff5cc4d
Dump Tests now successfully executes and outputs a file. Doesn't have…
kkeirstead Aug 26, 2021
ffc3f1b
Discovered that the file I was returning was the temporary one, and t…
kkeirstead Aug 26, 2021
346af25
Realized that we aren't supporting the null scenario for egress; inte…
kkeirstead Aug 27, 2021
7649719
Merge branch 'feature/triggers' of https://github.com/dotnet/dotnet-m…
kkeirstead Aug 30, 2021
abff7cc
Merge branch 'feature/triggers' of https://github.com/dotnet/dotnet-m…
kkeirstead Aug 30, 2021
f24cc13
Not currently in a functioning state (for tests); need to ask Justin …
kkeirstead Aug 31, 2021
8809244
Removed a lot of commented out code that was no longer relevant and w…
kkeirstead Sep 1, 2021
77c4619
File egress test is now passing and file is being egressed to the spe…
kkeirstead Sep 2, 2021
7781356
Reorganization and some code clean-up.
kkeirstead Sep 2, 2021
47f4568
Some more clean-up and commenting; decided not to add test for invali…
kkeirstead Sep 2, 2021
f67ff51
Temp changes that should go in before PR; not passing tests though fo…
kkeirstead Sep 2, 2021
279c0e8
Small tweaks; test command is succeeding (may have been an issue in VS)
kkeirstead Sep 3, 2021
d3804db
Merged with feature/triggers; currently having an issue where it won'…
kkeirstead Sep 3, 2021
3e90a00
Removed an extraneous comment.
kkeirstead Sep 3, 2021
2e92313
Significant refactoring for Wiktor and Justin; overall functionality …
kkeirstead Sep 7, 2021
00bd057
Merge branch 'feature/triggers' into kkeirstead/triggers/DumpAction
kkeirstead Sep 7, 2021
29e1cad
Resolving an error that resulted from GitHub's automatic merge.
kkeirstead Sep 7, 2021
bdc4847
This appears to have resolved the merge conflict issues (mostly surro…
kkeirstead Sep 8, 2021
664aea2
Merge branch 'feature/triggers' into kkeirstead/triggers/DumpAction
kkeirstead Sep 8, 2021
527fb58
Slight refactoring to get a shared method out of DiagController and i…
kkeirstead Sep 8, 2021
894c214
Merge branch 'kkeirstead/triggers/DumpAction' of https://github.com/k…
kkeirstead Sep 8, 2021
da9d016
Still experimenting to get tests to pass. Issue appears to be with Fi…
kkeirstead Sep 9, 2021
6ff42bf
Changes for Justin and Wiktor
kkeirstead Sep 10, 2021
f707c78
More tweaks for Justin.
kkeirstead Sep 10, 2021
19ccda9
Formatting tweaks and removing some unused using statements.
kkeirstead Sep 13, 2021
6ffdb5b
Rename for Justin.
kkeirstead Sep 13, 2021
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
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ partial class DiagController
[ProducesWithProblemDetails(ContentTypes.ApplicationJsonSequence)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status429TooManyRequests)]
[ProducesResponseType(typeof(void), StatusCodes.Status202Accepted)]
[RequestLimit(LimitKey = ArtifactType_Metrics)]
[RequestLimit(LimitKey = Utilities.ArtifactType_Metrics)]
[EgressValidation]
public Task<ActionResult> CaptureMetrics(
[FromQuery]
Expand Down Expand Up @@ -72,13 +72,13 @@ public Task<ActionResult> CaptureMetrics(
await eventCounterPipeline.RunAsync(token);
};

return await Result(ArtifactType_Metrics,
return await Result(Utilities.ArtifactType_Metrics,
egressProvider,
action,
fileName,
ContentTypes.ApplicationJsonSequence,
processInfo.EndpointInfo);
}, processKey, ArtifactType_Metrics);
}, processKey, Utilities.ArtifactType_Metrics);
}

/// <summary>
Expand All @@ -95,7 +95,7 @@ public Task<ActionResult> CaptureMetrics(
[ProducesWithProblemDetails(ContentTypes.ApplicationJsonSequence)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status429TooManyRequests)]
[ProducesResponseType(typeof(void), StatusCodes.Status202Accepted)]
[RequestLimit(LimitKey = ArtifactType_Metrics)]
[RequestLimit(LimitKey = Utilities.ArtifactType_Metrics)]
[EgressValidation]
public Task<ActionResult> CaptureMetricsCustom(
[FromBody][Required]
Expand Down Expand Up @@ -135,16 +135,16 @@ public Task<ActionResult> CaptureMetricsCustom(
await eventCounterPipeline.RunAsync(token);
};

return await Result(ArtifactType_Metrics,
return await Result(Utilities.ArtifactType_Metrics,
egressProvider,
action,
fileName,
ContentTypes.ApplicationJsonSequence,
processInfo.EndpointInfo);
}, processKey, ArtifactType_Metrics);
}, processKey, Utilities.ArtifactType_Metrics);
}

private static string GetMetricFilename(IProcessInfo processInfo) =>
FormattableString.Invariant($"{GetFileNameTimeStampUtcNow()}_{processInfo.EndpointInfo.ProcessId}.metrics.json");
FormattableString.Invariant($"{Utilities.GetFileNameTimeStampUtcNow()}_{processInfo.EndpointInfo.ProcessId}.metrics.json");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,6 @@ namespace Microsoft.Diagnostics.Monitoring.WebApi.Controllers
[ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
public partial class DiagController : ControllerBase
{
public const string ArtifactType_Dump = "dump";
public const string ArtifactType_GCDump = "gcdump";
public const string ArtifactType_Logs = "logs";
public const string ArtifactType_Trace = "trace";
public const string ArtifactType_Metrics = "collectmetrics";

private const Models.TraceProfile DefaultTraceProfiles = Models.TraceProfile.Cpu | Models.TraceProfile.Http | Models.TraceProfile.Metrics;
private static readonly MediaTypeHeaderValue NdJsonHeader = new MediaTypeHeaderValue(ContentTypes.ApplicationNdJson);
private static readonly MediaTypeHeaderValue JsonSequenceHeader = new MediaTypeHeaderValue(ContentTypes.ApplicationJsonSequence);
Expand All @@ -53,6 +47,7 @@ public partial class DiagController : ControllerBase
private readonly IDiagnosticServices _diagnosticServices;
private readonly IOptions<DiagnosticPortOptions> _diagnosticPortOptions;
private readonly EgressOperationStore _operationsStore;
private readonly IDumpService _dumpService;

public DiagController(ILogger<DiagController> logger,
IServiceProvider serviceProvider)
Expand All @@ -61,6 +56,7 @@ public DiagController(ILogger<DiagController> logger,
_diagnosticServices = serviceProvider.GetRequiredService<IDiagnosticServices>();
_diagnosticPortOptions = serviceProvider.GetService<IOptions<DiagnosticPortOptions>>();
_operationsStore = serviceProvider.GetRequiredService<EgressOperationStore>();
_dumpService = serviceProvider.GetRequiredService<IDumpService>();
}

/// <summary>
Expand Down Expand Up @@ -194,7 +190,7 @@ public Task<ActionResult<Dictionary<string, string>>> GetProcessEnvironment(
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status429TooManyRequests)]
[ProducesResponseType(typeof(FileResult), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(void), StatusCodes.Status202Accepted)]
[RequestLimit(LimitKey = ArtifactType_Dump)]
[RequestLimit(LimitKey = Utilities.ArtifactType_Dump)]
[EgressValidation]
public Task<ActionResult> CaptureDump(
[FromQuery]
Expand All @@ -212,13 +208,11 @@ public Task<ActionResult> CaptureDump(

return InvokeForProcess(async processInfo =>
{
string dumpFileName = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ?
FormattableString.Invariant($"dump_{GetFileNameTimeStampUtcNow()}.dmp") :
FormattableString.Invariant($"core_{GetFileNameTimeStampUtcNow()}");
string dumpFileName = Utilities.GenerateDumpFileName();

if (string.IsNullOrEmpty(egressProvider))
{
Stream dumpStream = await _diagnosticServices.GetDump(processInfo, type, HttpContext.RequestAborted);
Stream dumpStream = await _dumpService.DumpAsync(processInfo.EndpointInfo, type, HttpContext.RequestAborted);

_logger.WrittenToHttpStream();
//Compression is done automatically by the response
Expand All @@ -227,19 +221,17 @@ public Task<ActionResult> CaptureDump(
}
else
{
KeyValueLogScope scope = new KeyValueLogScope();
scope.AddArtifactType(ArtifactType_Dump);
scope.AddEndpointInfo(processInfo.EndpointInfo);
KeyValueLogScope scope = Utilities.GetScope(Utilities.ArtifactType_Dump, processInfo.EndpointInfo);

return await SendToEgress(new EgressOperation(
token => _diagnosticServices.GetDump(processInfo, type, token),
token => _dumpService.DumpAsync(processInfo.EndpointInfo, type, token),
egressProvider,
dumpFileName,
processInfo.EndpointInfo,
ContentTypes.ApplicationOctetStream,
scope), limitKey: ArtifactType_Dump);
scope), limitKey: Utilities.ArtifactType_Dump);
}
}, processKey, ArtifactType_Dump);
}, processKey, Utilities.ArtifactType_Dump);
}

/// <summary>
Expand All @@ -257,7 +249,7 @@ public Task<ActionResult> CaptureDump(
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status429TooManyRequests)]
[ProducesResponseType(typeof(FileResult), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(void), StatusCodes.Status202Accepted)]
[RequestLimit(LimitKey = ArtifactType_GCDump)]
[RequestLimit(LimitKey = Utilities.ArtifactType_GCDump)]
[EgressValidation]
public Task<ActionResult> CaptureGcDump(
[FromQuery]
Expand All @@ -273,7 +265,7 @@ public Task<ActionResult> CaptureGcDump(

return InvokeForProcess(processInfo =>
{
string fileName = FormattableString.Invariant($"{GetFileNameTimeStampUtcNow()}_{processInfo.EndpointInfo.ProcessId}.gcdump");
string fileName = FormattableString.Invariant($"{Utilities.GetFileNameTimeStampUtcNow()}_{processInfo.EndpointInfo.ProcessId}.gcdump");

Func<CancellationToken, Task<IFastSerializable>> action = async (token) => {
var graph = new Graphs.MemoryGraph(50_000);
Expand All @@ -295,13 +287,13 @@ public Task<ActionResult> CaptureGcDump(
};

return Result(
ArtifactType_GCDump,
Utilities.ArtifactType_GCDump,
egressProvider,
ConvertFastSerializeAction(action),
fileName,
ContentTypes.ApplicationOctetStream,
processInfo.EndpointInfo);
}, processKey, ArtifactType_GCDump);
}, processKey, Utilities.ArtifactType_GCDump);
}

/// <summary>
Expand All @@ -321,7 +313,7 @@ public Task<ActionResult> CaptureGcDump(
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status429TooManyRequests)]
[ProducesResponseType(typeof(FileResult), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(void), StatusCodes.Status202Accepted)]
[RequestLimit(LimitKey = ArtifactType_Trace)]
[RequestLimit(LimitKey = Utilities.ArtifactType_Trace)]
[EgressValidation]
public Task<ActionResult> CaptureTrace(
[FromQuery]
Expand Down Expand Up @@ -370,7 +362,7 @@ public Task<ActionResult> CaptureTrace(
var aggregateConfiguration = new AggregateSourceConfiguration(configurations.ToArray());

return StartTrace(processInfo, aggregateConfiguration, duration, egressProvider);
}, processKey, ArtifactType_Trace);
}, processKey, Utilities.ArtifactType_Trace);
}

/// <summary>
Expand All @@ -389,7 +381,7 @@ public Task<ActionResult> CaptureTrace(
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status429TooManyRequests)]
[ProducesResponseType(typeof(FileResult), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(void), StatusCodes.Status202Accepted)]
[RequestLimit(LimitKey = ArtifactType_Trace)]
[RequestLimit(LimitKey = Utilities.ArtifactType_Trace)]
[EgressValidation]
public Task<ActionResult> CaptureTraceCustom(
[FromBody][Required]
Expand Down Expand Up @@ -434,7 +426,7 @@ public Task<ActionResult> CaptureTraceCustom(
bufferSizeInMB: configuration.BufferSizeInMB);

return StartTrace(processInfo, traceConfiguration, duration, egressProvider);
}, processKey, ArtifactType_Trace);
}, processKey, Utilities.ArtifactType_Trace);
}

/// <summary>
Expand All @@ -451,7 +443,7 @@ public Task<ActionResult> CaptureTraceCustom(
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status429TooManyRequests)]
[ProducesResponseType(typeof(string), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(void), StatusCodes.Status202Accepted)]
[RequestLimit(LimitKey = ArtifactType_Logs)]
[RequestLimit(LimitKey = Utilities.ArtifactType_Logs)]
[EgressValidation]
public Task<ActionResult> CaptureLogs(
[FromQuery]
Expand Down Expand Up @@ -490,7 +482,7 @@ public Task<ActionResult> CaptureLogs(
}

return StartLogs(processInfo, settings, egressProvider);
}, processKey, ArtifactType_Logs);
}, processKey, Utilities.ArtifactType_Logs);
}

/// <summary>
Expand All @@ -507,7 +499,7 @@ public Task<ActionResult> CaptureLogs(
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status429TooManyRequests)]
[ProducesResponseType(typeof(string), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(void), StatusCodes.Status202Accepted)]
[RequestLimit(LimitKey = ArtifactType_Logs)]
[RequestLimit(LimitKey = Utilities.ArtifactType_Logs)]
[EgressValidation]
public Task<ActionResult> CaptureLogsCustom(
[FromBody]
Expand Down Expand Up @@ -538,7 +530,7 @@ public Task<ActionResult> CaptureLogsCustom(
};

return StartLogs(processInfo, settings, egressProvider);
}, processKey, ArtifactType_Logs);
}, processKey, Utilities.ArtifactType_Logs);
}

/// <summary>
Expand Down Expand Up @@ -601,7 +593,7 @@ private Task<ActionResult> StartTrace(
TimeSpan duration,
string egressProvider)
{
string fileName = FormattableString.Invariant($"{GetFileNameTimeStampUtcNow()}_{processInfo.EndpointInfo.ProcessId}.nettrace");
string fileName = FormattableString.Invariant($"{Utilities.GetFileNameTimeStampUtcNow()}_{processInfo.EndpointInfo.ProcessId}.nettrace");

Func<Stream, CancellationToken, Task> action = async (outputStream, token) =>
{
Expand All @@ -624,7 +616,7 @@ private Task<ActionResult> StartTrace(
};

return Result(
ArtifactType_Trace,
Utilities.ArtifactType_Trace,
egressProvider,
action,
fileName,
Expand All @@ -643,7 +635,7 @@ private Task<ActionResult> StartLogs(
return Task.FromResult<ActionResult>(this.NotAcceptable());
}

string fileName = FormattableString.Invariant($"{GetFileNameTimeStampUtcNow()}_{processInfo.EndpointInfo.ProcessId}.txt");
string fileName = FormattableString.Invariant($"{Utilities.GetFileNameTimeStampUtcNow()}_{processInfo.EndpointInfo.ProcessId}.txt");
string contentType = ContentTypes.TextEventStream;

if (format == LogFormat.EventStream)
Expand Down Expand Up @@ -672,7 +664,7 @@ private Task<ActionResult> StartLogs(
};

return Result(
ArtifactType_Logs,
Utilities.ArtifactType_Logs,
egressProvider,
action,
fileName,
Expand All @@ -693,11 +685,6 @@ private static TimeSpan ConvertSecondsToTimeSpan(int durationSeconds)
return (pid == null && uid == null && name == null) ? null : new ProcessKey(pid, uid, name);
}

private static string GetFileNameTimeStampUtcNow()
{
return DateTime.UtcNow.ToString("yyyyMMdd_HHmmss");
}

private static LogFormat ComputeLogFormat(IList<MediaTypeHeaderValue> acceptedHeaders)
{
if (acceptedHeaders == null)
Expand Down Expand Up @@ -741,9 +728,7 @@ private Task<ActionResult> Result(
IEndpointInfo endpointInfo,
bool asAttachment = true)
{
KeyValueLogScope scope = new KeyValueLogScope();
scope.AddArtifactType(artifactType);
scope.AddEndpointInfo(endpointInfo);
KeyValueLogScope scope = Utilities.GetScope(artifactType, endpointInfo);

if (string.IsNullOrEmpty(providerName))
{
Expand Down
48 changes: 0 additions & 48 deletions src/Microsoft.Diagnostics.Monitoring.WebApi/DiagnosticServices.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
Expand All @@ -29,15 +27,12 @@ internal sealed class DiagnosticServices : IDiagnosticServices

private readonly IEndpointInfoSourceInternal _endpointInfoSource;
private readonly CancellationTokenSource _tokenSource = new CancellationTokenSource();
private readonly IOptionsMonitor<StorageOptions> _storageOptions;
private readonly IOptionsMonitor<ProcessFilterOptions> _defaultProcessOptions;

public DiagnosticServices(IEndpointInfoSource endpointInfoSource,
IOptionsMonitor<StorageOptions> storageOptions,
IOptionsMonitor<ProcessFilterOptions> defaultProcessMonitor)
{
_endpointInfoSource = (IEndpointInfoSourceInternal)endpointInfoSource;
_storageOptions = storageOptions;
_defaultProcessOptions = defaultProcessMonitor;
}

Expand Down Expand Up @@ -81,48 +76,6 @@ public async Task<IEnumerable<IProcessInfo>> GetProcessesAsync(DiagProcessFilter

return processes.ToArray();
}
public async Task<Stream> GetDump(IProcessInfo pi, Models.DumpType mode, CancellationToken token)
{
string dumpFilePath = Path.Combine(_storageOptions.CurrentValue.DumpTempFolder, FormattableString.Invariant($"{Guid.NewGuid()}_{pi.EndpointInfo.ProcessId}"));
DumpType dumpType = MapDumpType(mode);

if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
// Get the process
Process process = Process.GetProcessById(pi.EndpointInfo.ProcessId);
await Dumper.CollectDumpAsync(process, dumpFilePath, dumpType);
}
else
{
var client = new DiagnosticsClient(pi.EndpointInfo.Endpoint);
await client.WriteDumpAsync(dumpType, dumpFilePath, logDumpGeneration: false, token);
}

return new AutoDeleteFileStream(dumpFilePath);
}

private static DumpType MapDumpType(Models.DumpType dumpType)
{
switch (dumpType)
{
case Models.DumpType.Full:
return DumpType.Full;
case Models.DumpType.WithHeap:
return DumpType.WithHeap;
case Models.DumpType.Triage:
return DumpType.Triage;
case Models.DumpType.Mini:
return DumpType.Normal;
default:
throw new ArgumentException(
string.Format(
CultureInfo.InvariantCulture,
Strings.ErrorMessage_UnexpectedType,
nameof(DumpType),
dumpType),
nameof(dumpType));
}
}

public Task<IProcessInfo> GetProcessAsync(ProcessKey? processKey, CancellationToken token)
{
Expand Down Expand Up @@ -179,7 +132,6 @@ public AutoDeleteFileStream(string path) : base(path, FileMode.Open, FileAccess.
public override bool CanSeek => false;
}


private sealed class ProcessInfo : IProcessInfo
{
// String returned for a process field when its value could not be retrieved. This is the same
Expand Down
Loading