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

Enable Custom Artifact Names with New Tokens #6675

Merged
merged 26 commits into from
Aug 5, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
0081dfd
Initial design
wsugarman May 18, 2024
1408cf6
Add proper unix seconds support
wsugarman May 18, 2024
8020845
Fix default
wsugarman May 18, 2024
82e7193
Merge branch 'main' into dotnet-dump-template
wsugarman May 18, 2024
2ae837f
Merge remote-tracking branch 'origin/main' into dotnet-dump-template
wsugarman Jun 2, 2024
38c3071
Add host and time
wsugarman Jun 2, 2024
29fd72a
Revert "Fix default"
wsugarman Jun 2, 2024
4b46fde
Revert "Add proper unix seconds support"
wsugarman Jun 2, 2024
40024fb
Revert "Initial design"
wsugarman Jun 2, 2024
680381e
Change pattern
wsugarman Jun 3, 2024
ab86bd5
Merge branch 'main' into dotnet-dump-template
wsugarman Jun 3, 2024
ccad5c3
Use default artifact name for API
wsugarman Jun 3, 2024
adf6cc8
Merge branch 'dotnet-dump-template' of https://github.com/wsugarman/d…
wsugarman Jun 3, 2024
42224a7
Merge branch 'main' into dotnet-dump-template
wsugarman Jun 21, 2024
562d0b6
Create HostInfo
wsugarman Jul 5, 2024
b1e300c
Merge main
wsugarman Jul 6, 2024
501f6c2
Fix nullability
wsugarman Jul 6, 2024
adb22ef
Add E2E tests for most actions
wsugarman Jul 7, 2024
463aa7c
Nit
wsugarman Jul 7, 2024
1c3d0bb
Merge in main
wsugarman Jul 27, 2024
c23a94f
Update schema.json
wsugarman Jul 27, 2024
b6a7693
Nit
wsugarman Jul 27, 2024
40ea154
Merge branch 'main' into dotnet-dump-template
wsugarman Aug 1, 2024
092c607
nit: spelling mistake
wsugarman Aug 1, 2024
91a7c2d
Merge branch 'main' into dotnet-dump-template
wsugarman Aug 1, 2024
f9b2e4b
Merge branch 'main' into dotnet-dump-template
wsugarman Aug 1, 2024
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

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -773,4 +773,8 @@
<value>The expected value of the 'iss' or Issuer field in the JWT (JSON Web Token).</value>
<comment>The description provided for the Issuer parameter on MonitorApiKeyOptions.</comment>
</data>
</root>
<data name="DisplayAttributeDescription_StorageOptions_DumpFileNameTemplate" xml:space="preserve">
<value>The template used for the name of dump files. Defaults to a name based on the current time and OS.</value>
<comment>The description provided for the DumpFileNameTemplate parameter on StorageOptions.</comment>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ public class StorageOptions
Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_StorageOptions_DumpTempFolder))]
public string DumpTempFolder { get; set; }

[Display(
ResourceType = typeof(OptionsDisplayStrings),
Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_StorageOptions_DumpFileNameTemplate))]
public string DumpFileNameTemplate { get; set; }

[Experimental]
[Display(
ResourceType = typeof(OptionsDisplayStrings),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ public Task<ActionResult> CaptureDump(
processInfo => Result(
Utilities.ArtifactType_Dump,
egressProvider,
_dumpOperationFactory.Create(processInfo.EndpointInfo, type),
_dumpOperationFactory.Create(processInfo, type),
processInfo,
tags),
processKey,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ internal interface IDumpOperationFactory
/// <summary>
/// Creates an operation that produces a dump artifact.
/// </summary>
IArtifactOperation Create(
IEndpointInfo endpointInfo,
DumpType dumpType);
/// <param name="processInfo">The target of the dump artifact.</param>
/// <param name="dumpType">Specifies the type of dump.</param>
/// <returns>The corresponding operation responsible for producing the artifact.</returns>
IArtifactOperation Create(IProcessInfo processInfo, DumpType dumpType);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,15 @@ public static TimeSpan ConvertSecondsToTimeSpan(int durationSeconds)
TimeSpan.FromSeconds(durationSeconds);
}

public static string GetFileNameTimeStampUtcNow()
public static string GetFileNameTimeStamp(DateTimeOffset dt)
{
// spell-checker:disable-next
return DateTime.UtcNow.ToString("yyyyMMdd_HHmmss_fff");
return dt.ToString("yyyyMMdd_HHmmss_fff");
}

public static string GetFileNameTimeStampUtcNow()
{
return GetFileNameTimeStamp(DateTimeOffset.UtcNow);
}

public static KeyValueLogScope CreateArtifactScope(string artifactType, IEndpointInfo endpointInfo)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ protected override EgressOperation CreateArtifactOperation(CollectionRuleMetadat

KeyValueLogScope scope = Utils.CreateArtifactScope(Utils.ArtifactType_Dump, EndpointInfo);

IArtifactOperation dumpOperation = _dumpOperationFactory.Create(EndpointInfo, dumpType);
IArtifactOperation dumpOperation = _dumpOperationFactory.Create(ProcessInfo, dumpType);

EgressOperation egressOperation = new EgressOperation(
dumpOperation,
Expand Down
99 changes: 99 additions & 0 deletions src/Tools/dotnet-monitor/Dumps/DumpFilePathTemplate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.Diagnostics.Monitoring.WebApi;
using System;
using System.Globalization;
using System.Net;
using System.Text;
using Utils = Microsoft.Diagnostics.Monitoring.WebApi.Utilities;

namespace Microsoft.Diagnostics.Tools.Monitor
{
internal sealed class DumpFilePathTemplate
{
private const char PercentSpecifier = '%';
private const char ProcessIdSpecifier = 'p';
private const char ExecutableSpecifier = 'e';
private const char HostSpecifier = 'h';
private const char TimeSpecifier = 't';
private const char DateTimeSpecifier = 'd';
wsugarman marked this conversation as resolved.
Show resolved Hide resolved

private const int PercentPosition = 0;
private const int ProcessIdPosition = 1;
private const int ExecutablePosition = 2;
private const int HostPosition = 3;
private const int TimePosition = 4;
private const int DateTimePosition = 5;

private readonly CompositeFormat _format;

private DumpFilePathTemplate(CompositeFormat format)
{
_format = format;
}

public static DumpFilePathTemplate Parse(string template)
{
StringBuilder builder = new();
for (int i = 0; i < template.Length; i++)
{
switch (template[i])
{
case '{':
builder.Append('{');
goto default;
case '}':
builder.Append('}');
goto default;
case '%':
if (i == template.Length - 1)
{
throw new FormatException(string.Format(CultureInfo.InvariantCulture, Strings.ErrorMessage_InvalidDumpFileTemplateSpecifier, '%'));
}

char specifier = template[++i];
int position = specifier switch
{
PercentSpecifier => PercentPosition,
ProcessIdSpecifier => ProcessIdPosition,
ExecutableSpecifier => ExecutablePosition,
HostSpecifier => HostPosition,
TimeSpecifier => TimePosition,
DateTimeSpecifier => DateTimePosition,
_ => throw new FormatException(string.Format(CultureInfo.InvariantCulture, Strings.ErrorMessage_InvalidDumpFileTemplateSpecifier, "%" + specifier)),
};

builder.Append('{');
builder.Append(position);
builder.Append('}');
break;
default:
builder.Append(template[i]);
break;
}
}

return new DumpFilePathTemplate(CompositeFormat.Parse(builder.ToString()));
}

public string ToString(IProcessInfo processInfo)
{
return ToString(processInfo, TimeProvider.System);
}

internal string ToString(IProcessInfo processInfo, TimeProvider timeProvider)
{
DateTimeOffset utcNow = timeProvider.GetUtcNow();
return string.Format(
CultureInfo.InvariantCulture,
_format,
'%',
processInfo.EndpointInfo.ProcessId,
processInfo.ProcessName,
Dns.GetHostName(),
utcNow.ToUnixTimeSeconds(),
Utils.GetFileNameTimeStamp(utcNow));
}
}
}
20 changes: 7 additions & 13 deletions src/Tools/dotnet-monitor/Dumps/DumpOperation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,44 +4,38 @@
using Microsoft.Diagnostics.Monitoring;
using Microsoft.Diagnostics.Monitoring.WebApi;
using Microsoft.Diagnostics.Monitoring.WebApi.Models;
using Microsoft.Extensions.Logging;
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Utils = Microsoft.Diagnostics.Monitoring.WebApi.Utilities;

namespace Microsoft.Diagnostics.Tools.Monitor
{
internal sealed class DumpOperation : IArtifactOperation
{
private readonly IDumpService _dumpService;
private readonly DumpType _dumpType;
private readonly IEndpointInfo _endpointInfo;
private readonly ILogger _logger;
private readonly IProcessInfo _processInfo;
private readonly DumpFilePathTemplate _filePathTemplate;
private readonly TaskCompletionSource _startCompletionSource = new(TaskCreationOptions.RunContinuationsAsynchronously);

public DumpOperation(IEndpointInfo endpointInfo, IDumpService dumpService, DumpType dumpType, ILogger logger)
public DumpOperation(IProcessInfo processInfo, IDumpService dumpService, DumpType dumpType, DumpFilePathTemplate filePathTemplate)
{
_dumpService = dumpService;
_dumpType = dumpType;
_endpointInfo = endpointInfo;
_logger = logger;
_processInfo = processInfo;
_filePathTemplate = filePathTemplate;
}

public string GenerateFileName()
{
return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ?
FormattableString.Invariant($"dump_{Utils.GetFileNameTimeStampUtcNow()}.dmp") :
FormattableString.Invariant($"core_{Utils.GetFileNameTimeStampUtcNow()}");
return _filePathTemplate.ToString(_processInfo);
}

public async Task ExecuteAsync(Stream outputStream, CancellationToken token)
{
_startCompletionSource.TrySetResult();

using Stream dumpStream = await _dumpService.DumpAsync(_endpointInfo, _dumpType, token);
using Stream dumpStream = await _dumpService.DumpAsync(_processInfo.EndpointInfo, _dumpType, token);

await dumpStream.CopyToAsync(outputStream, token);
}
Expand Down
13 changes: 7 additions & 6 deletions src/Tools/dotnet-monitor/Dumps/DumpOperationFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,25 @@

using Microsoft.Diagnostics.Monitoring.WebApi;
using Microsoft.Diagnostics.Monitoring.WebApi.Models;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace Microsoft.Diagnostics.Tools.Monitor
{
internal sealed class DumpOperationFactory : IDumpOperationFactory
{
private readonly IDumpService _dumpService;
private readonly ILogger<DumpOperation> _logger;
private readonly IOptionsMonitor<StorageOptions> _options;

public DumpOperationFactory(IDumpService dumpService, ILogger<DumpOperation> logger)
public DumpOperationFactory(IDumpService dumpService, IOptionsMonitor<StorageOptions> options)
{
_dumpService = dumpService;
_logger = logger;
_options = options;
}

public IArtifactOperation Create(IEndpointInfo endpointInfo, DumpType dumpType)
public IArtifactOperation Create(IProcessInfo processInfo, DumpType dumpType)
{
return new DumpOperation(endpointInfo, _dumpService, dumpType, _logger);
StorageOptions options = _options.CurrentValue;
return new DumpOperation(processInfo, _dumpService, dumpType, DumpFilePathTemplate.Parse(options.DumpFileNameTemplate));
}
}
}
6 changes: 6 additions & 0 deletions src/Tools/dotnet-monitor/StoragePostConfigureOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Microsoft.Diagnostics.Monitoring.WebApi;
using Microsoft.Extensions.Options;
using System.IO;
using System.Runtime.InteropServices;

namespace Microsoft.Diagnostics.Tools.Monitor
{
Expand Down Expand Up @@ -34,6 +35,11 @@ void IPostConfigureOptions<StorageOptions>.PostConfigure(string name, StorageOpt
options.SharedLibraryPath = Path.Combine(options.DefaultSharedPath, DefaultSharedPathLibrariesFolderName);
}
}

if (string.IsNullOrEmpty(options.DumpFileNameTemplate))
{
options.DumpFileNameTemplate = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "dump_%d.dmp" : "core_%d";
}
}
}
}
9 changes: 9 additions & 0 deletions src/Tools/dotnet-monitor/Strings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions src/Tools/dotnet-monitor/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -949,4 +949,8 @@
<value>The expiration time on or after the generated key will no longer be accepted. This is a time span offset (e.g. "7.00:00:00" for 7 days) that will be added to the current date time to create the expiration date time.</value>
<comment>Gets the string to display in help that explains what the '--expiration' option does.</comment>
</data>
<data name="ErrorMessage_InvalidDumpFileTemplateSpecifier" xml:space="preserve">
<value>DumpFileTemplate contains an invalid template specifier {0}.</value>
<comment>Gets the format string for an invalid specifier.</comment>
</data>
</root>
Loading