Skip to content
This repository was archived by the owner on Jan 21, 2026. It is now read-only.
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
1 change: 1 addition & 0 deletions TELEMETRY.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ The telemetry feature collects the following data:
| >=5.0 | For the `pref` command, whether a `get` or `set` was issued and which preference was accessed. If not a well-known preference, the name is hashed. The value is not collected. |
| >=5.0 | For the `set header` command, the header name being set. If not a well-known header, the name is hashed. The value is not collected. |
| >=5.0 | For the `connect` command, whether or not a specific special-case for `dotnet new webapi` was used and, whether or not it was bypassed via preference. |
| >=5.0 | For all HTTP commands (e.g. GET, POST, PUT, etc), whether or not each of the options was specified. The values of the options are not collected. |

## See also

Expand Down
28 changes: 26 additions & 2 deletions src/Microsoft.HttpRepl/Commands/BaseHttpCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
using Microsoft.HttpRepl.Preferences;
using Microsoft.HttpRepl.Resources;
using Microsoft.HttpRepl.Suggestions;
using Microsoft.HttpRepl.Telemetry;
using Microsoft.HttpRepl.Telemetry.Events;
using Microsoft.Repl;
using Microsoft.Repl.Commanding;
using Microsoft.Repl.ConsoleHandling;
Expand Down Expand Up @@ -49,17 +51,19 @@ public abstract class BaseHttpCommand : CommandWithStructuredInputBase<HttpState

private readonly IFileSystem _fileSystem;
private readonly IPreferences _preferences;
private readonly ITelemetry _telemetry;

public override string Name => Verb;

protected abstract string Verb { get; }

protected abstract bool RequiresBody { get; }

protected BaseHttpCommand(IFileSystem fileSystem, IPreferences preferences)
protected BaseHttpCommand(IFileSystem fileSystem, IPreferences preferences, ITelemetry telemetry)
{
_fileSystem = fileSystem;
_preferences = preferences;
_telemetry = telemetry;
}

public override CommandInputSpecification InputSpec
Expand Down Expand Up @@ -101,10 +105,12 @@ protected override async Task ExecuteAsync(IShellState shellState, HttpState pro

if (programState.BaseAddress == null && (commandInput.Arguments.Count == 0 || !Uri.TryCreate(commandInput.Arguments[0].Text, UriKind.Absolute, out _)))
{
shellState.ConsoleManager.Error.WriteLine(Resources.Strings.Error_NoBasePath.SetColor(programState.ErrorColor));
shellState.ConsoleManager.Error.WriteLine(Strings.Error_NoBasePath.SetColor(programState.ErrorColor));
return;
}

SendTelemetry(commandInput);

if (programState.SwaggerEndpoint != null)
{
await CreateDirectoryStructureForSwaggerEndpointAsync(shellState, programState, cancellationToken).ConfigureAwait(false);
Expand Down Expand Up @@ -750,5 +756,23 @@ private static string GetExampleBody(string path, ref string contentType, string
IDirectoryStructure structure = httpState.Structure?.TraverseTo(rootRelativePath);
return structure?.RequestInfo?.GetRequestBodyForContentType(ref contentType, method);
}

private void SendTelemetry(DefaultCommandInput<ICoreParseResult> commandInput)
{
HttpCommandEvent httpCommandEvent = new HttpCommandEvent(
method: Verb.ToUpperInvariant(),
isPathSpecified: commandInput.Arguments.Count > 0,
isHeaderSpecified: commandInput.Options[HeaderOption].Any(),
isResponseHeadersFileSpecified: commandInput.Options[ResponseHeadersFileOption].Any(),
isResponseBodyFileSpecified: commandInput.Options[ResponseBodyFileOption].Any(),
isNoFormattingSpecified: commandInput.Options[NoFormattingOption].Any(),
isStreamingSpecified: commandInput.Options[StreamingOption].Any(),
isNoBodySpecified: RequiresBody && commandInput.Options[NoBodyOption].Any(),
isRequestBodyFileSpecified: RequiresBody && commandInput.Options[BodyFileOption].Any(),
isRequestBodyContentSpecified: RequiresBody && commandInput.Options[BodyContentOption].Any()
);

_telemetry.TrackEvent(httpCommandEvent);
}
}
}
3 changes: 2 additions & 1 deletion src/Microsoft.HttpRepl/Commands/DeleteCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@

using Microsoft.HttpRepl.FileSystem;
using Microsoft.HttpRepl.Preferences;
using Microsoft.HttpRepl.Telemetry;

namespace Microsoft.HttpRepl.Commands
{
public class DeleteCommand : BaseHttpCommand
{
public DeleteCommand(IFileSystem fileSystem, IPreferences preferences) : base(fileSystem, preferences) { }
public DeleteCommand(IFileSystem fileSystem, IPreferences preferences, ITelemetry telemetry) : base(fileSystem, preferences, telemetry) { }

protected override string Verb => "delete";

Expand Down
3 changes: 2 additions & 1 deletion src/Microsoft.HttpRepl/Commands/GetCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@

using Microsoft.HttpRepl.FileSystem;
using Microsoft.HttpRepl.Preferences;
using Microsoft.HttpRepl.Telemetry;

namespace Microsoft.HttpRepl.Commands
{
public class GetCommand : BaseHttpCommand
{
public GetCommand(IFileSystem fileSystem, IPreferences preferences) : base(fileSystem, preferences) { }
public GetCommand(IFileSystem fileSystem, IPreferences preferences, ITelemetry telemetry) : base(fileSystem, preferences, telemetry) { }

protected override string Verb => "get";

Expand Down
3 changes: 2 additions & 1 deletion src/Microsoft.HttpRepl/Commands/HeadCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@

using Microsoft.HttpRepl.FileSystem;
using Microsoft.HttpRepl.Preferences;
using Microsoft.HttpRepl.Telemetry;

namespace Microsoft.HttpRepl.Commands
{
public class HeadCommand : BaseHttpCommand
{
public HeadCommand(IFileSystem fileSystem, IPreferences preferences) : base(fileSystem, preferences) { }
public HeadCommand(IFileSystem fileSystem, IPreferences preferences, ITelemetry telemetry) : base(fileSystem, preferences, telemetry) { }

protected override string Verb => "head";

Expand Down
3 changes: 2 additions & 1 deletion src/Microsoft.HttpRepl/Commands/OptionsCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@

using Microsoft.HttpRepl.FileSystem;
using Microsoft.HttpRepl.Preferences;
using Microsoft.HttpRepl.Telemetry;

namespace Microsoft.HttpRepl.Commands
{
public class OptionsCommand : BaseHttpCommand
{
public OptionsCommand(IFileSystem fileSystem, IPreferences preferences) : base(fileSystem, preferences) { }
public OptionsCommand(IFileSystem fileSystem, IPreferences preferences, ITelemetry telemetry) : base(fileSystem, preferences, telemetry) { }

protected override string Verb => "options";

Expand Down
3 changes: 2 additions & 1 deletion src/Microsoft.HttpRepl/Commands/PatchCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@

using Microsoft.HttpRepl.FileSystem;
using Microsoft.HttpRepl.Preferences;
using Microsoft.HttpRepl.Telemetry;

namespace Microsoft.HttpRepl.Commands
{
public class PatchCommand : BaseHttpCommand
{
public PatchCommand(IFileSystem fileSystem, IPreferences preferences) : base(fileSystem, preferences) { }
public PatchCommand(IFileSystem fileSystem, IPreferences preferences, ITelemetry telemetry) : base(fileSystem, preferences, telemetry) { }

protected override string Verb => "patch";

Expand Down
3 changes: 2 additions & 1 deletion src/Microsoft.HttpRepl/Commands/PostCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@

using Microsoft.HttpRepl.FileSystem;
using Microsoft.HttpRepl.Preferences;
using Microsoft.HttpRepl.Telemetry;

namespace Microsoft.HttpRepl.Commands
{
public class PostCommand : BaseHttpCommand
{
public PostCommand(IFileSystem fileSystem, IPreferences preferences) : base(fileSystem, preferences) { }
public PostCommand(IFileSystem fileSystem, IPreferences preferences, ITelemetry telemetry) : base(fileSystem, preferences, telemetry) { }

protected override string Verb => "post";

Expand Down
3 changes: 2 additions & 1 deletion src/Microsoft.HttpRepl/Commands/PutCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@

using Microsoft.HttpRepl.FileSystem;
using Microsoft.HttpRepl.Preferences;
using Microsoft.HttpRepl.Telemetry;

namespace Microsoft.HttpRepl.Commands
{
public class PutCommand : BaseHttpCommand
{
public PutCommand(IFileSystem fileSystem, IPreferences preferences) : base(fileSystem, preferences) { }
public PutCommand(IFileSystem fileSystem, IPreferences preferences, ITelemetry telemetry) : base(fileSystem, preferences, telemetry) { }

protected override string Verb => "put";

Expand Down
14 changes: 7 additions & 7 deletions src/Microsoft.HttpRepl/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,18 +110,18 @@ private static void ComposeDependencies(ref IConsoleManager consoleManager, ref
dispatcher.AddCommandWithTelemetry(telemetry, new ChangeDirectoryCommand());
dispatcher.AddCommandWithTelemetry(telemetry, new ClearCommand());
dispatcher.AddCommandWithTelemetry(telemetry, new ConnectCommand(preferences, telemetry));
dispatcher.AddCommandWithTelemetry(telemetry, new DeleteCommand(fileSystem, preferences));
dispatcher.AddCommandWithTelemetry(telemetry, new DeleteCommand(fileSystem, preferences, telemetry));
dispatcher.AddCommandWithTelemetry(telemetry, new EchoCommand());
dispatcher.AddCommandWithTelemetry(telemetry, new ExitCommand());
dispatcher.AddCommandWithTelemetry(telemetry, new HeadCommand(fileSystem, preferences));
dispatcher.AddCommandWithTelemetry(telemetry, new HeadCommand(fileSystem, preferences, telemetry));
dispatcher.AddCommandWithTelemetry(telemetry, new HelpCommand());
dispatcher.AddCommandWithTelemetry(telemetry, new GetCommand(fileSystem, preferences));
dispatcher.AddCommandWithTelemetry(telemetry, new GetCommand(fileSystem, preferences, telemetry));
dispatcher.AddCommandWithTelemetry(telemetry, new ListCommand(preferences));
dispatcher.AddCommandWithTelemetry(telemetry, new OptionsCommand(fileSystem, preferences));
dispatcher.AddCommandWithTelemetry(telemetry, new PatchCommand(fileSystem, preferences));
dispatcher.AddCommandWithTelemetry(telemetry, new OptionsCommand(fileSystem, preferences, telemetry));
dispatcher.AddCommandWithTelemetry(telemetry, new PatchCommand(fileSystem, preferences, telemetry));
dispatcher.AddCommandWithTelemetry(telemetry, new PrefCommand(preferences, telemetry));
dispatcher.AddCommandWithTelemetry(telemetry, new PostCommand(fileSystem, preferences));
dispatcher.AddCommandWithTelemetry(telemetry, new PutCommand(fileSystem, preferences));
dispatcher.AddCommandWithTelemetry(telemetry, new PostCommand(fileSystem, preferences, telemetry));
dispatcher.AddCommandWithTelemetry(telemetry, new PutCommand(fileSystem, preferences, telemetry));
dispatcher.AddCommandWithTelemetry(telemetry, new RunCommand(fileSystem));
dispatcher.AddCommandWithTelemetry(telemetry, new SetHeaderCommand(telemetry));
dispatcher.AddCommandWithTelemetry(telemetry, new UICommand(new UriLauncher(), preferences));
Expand Down
25 changes: 25 additions & 0 deletions src/Microsoft.HttpRepl/Telemetry/Events/HttpCommandEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

namespace Microsoft.HttpRepl.Telemetry.Events
{
internal class HttpCommandEvent : TelemetryEventBase
{
public HttpCommandEvent(string method, bool isPathSpecified, bool isHeaderSpecified, bool isResponseHeadersFileSpecified,
bool isResponseBodyFileSpecified, bool isNoFormattingSpecified, bool isStreamingSpecified,
bool isNoBodySpecified, bool isRequestBodyFileSpecified, bool isRequestBodyContentSpecified)
: base(TelemetryEventNames.HttpCommand)
{
SetProperty(TelemetryPropertyNames.HttpCommand_Method, method);
SetProperty(TelemetryPropertyNames.HttpCommand_PathSpecified, isPathSpecified);
SetProperty(TelemetryPropertyNames.HttpCommand_HeaderSpecified, isHeaderSpecified);
SetProperty(TelemetryPropertyNames.HttpCommand_ResponseHeadersFileSpecified, isResponseHeadersFileSpecified);
SetProperty(TelemetryPropertyNames.HttpCommand_ResponseBodyFileSpecified, isResponseBodyFileSpecified);
SetProperty(TelemetryPropertyNames.HttpCommand_NoFormattingSpecified, isNoFormattingSpecified);
SetProperty(TelemetryPropertyNames.HttpCommand_StreamingSpecified, isStreamingSpecified);
SetProperty(TelemetryPropertyNames.HttpCommand_NoBodySpecified, isNoBodySpecified);
SetProperty(TelemetryPropertyNames.HttpCommand_RequestBodyFileSpecified, isRequestBodyFileSpecified);
SetProperty(TelemetryPropertyNames.HttpCommand_RequestBodyContentSpecified, isRequestBodyContentSpecified);
}
}
}
12 changes: 12 additions & 0 deletions src/Microsoft.HttpRepl/Telemetry/TelemetryConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ internal class TelemetryEventNames
{
public const string CommandExecuted = nameof(CommandExecuted);
public const string Connect = nameof(Connect);
public const string HttpCommand = nameof(HttpCommand);
public const string Preference = nameof(Preference);
public const string SetHeader = nameof(SetHeader);
public const string Started = nameof(Started);
Expand All @@ -23,6 +24,17 @@ internal class TelemetryPropertyNames
public const string Connect_OpenApiSpecified = "OpenApiSpecified";
public const string Connect_RootSpecified = "RootSpecified";

public const string HttpCommand_HeaderSpecified = "HeaderSpecified";
public const string HttpCommand_Method = "Method";
public const string HttpCommand_NoBodySpecified = "NoBodySpecified";
public const string HttpCommand_NoFormattingSpecified = "NoFormattingSpecified";
public const string HttpCommand_PathSpecified = "PathSpecified";
public const string HttpCommand_RequestBodyContentSpecified = "RequestBodyContentSpecified";
public const string HttpCommand_RequestBodyFileSpecified = "RequestBodyFileSpecified";
public const string HttpCommand_ResponseHeadersFileSpecified = "ResponseHeadersFileSpecified";
public const string HttpCommand_ResponseBodyFileSpecified = "ResponseBodyFileSpecified";
public const string HttpCommand_StreamingSpecified = "StreamingSpecified";

public const string Preference_GetOrSet = "GetOrSet";
public const string Preference_PreferenceName = "PreferenceName";

Expand Down
6 changes: 3 additions & 3 deletions test/Microsoft.HttpRepl.Tests/Commands/DeleteCommandsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public async Task ExecuteAsync_WithNoBasePath_VerifyError()

string expectedErrorMessage = Strings.Error_NoBasePath.SetColor(httpState.ErrorColor);

DeleteCommand deleteCommand = new DeleteCommand(fileSystem, preferences);
DeleteCommand deleteCommand = new DeleteCommand(fileSystem, preferences, new NullTelemetry());
await deleteCommand.ExecuteAsync(shellState, httpState, parseResult, CancellationToken.None);

Assert.Equal(expectedErrorMessage, shellState.ErrorMessage);
Expand All @@ -63,7 +63,7 @@ public async Task ExecuteAsync_WithMultipartRoute_VerifyOutput()
out MockedFileSystem fileSystem,
out IPreferences preferences);

DeleteCommand deleteCommand = new DeleteCommand(fileSystem, preferences);
DeleteCommand deleteCommand = new DeleteCommand(fileSystem, preferences, new NullTelemetry());
await deleteCommand.ExecuteAsync(shellState, httpState, parseResult, CancellationToken.None);

string expectedResponse = "File path delete received successfully.";
Expand All @@ -87,7 +87,7 @@ public async Task ExecuteAsync_WithOnlyBaseAddress_VerifyOutput()
out MockedFileSystem fileSystem,
out IPreferences preferences);

DeleteCommand deleteCommand = new DeleteCommand(fileSystem, preferences);
DeleteCommand deleteCommand = new DeleteCommand(fileSystem, preferences, new NullTelemetry());
await deleteCommand.ExecuteAsync(shellState, httpState, parseResult, CancellationToken.None);

string expectedResponse = "Root delete received successfully.";
Expand Down
2 changes: 1 addition & 1 deletion test/Microsoft.HttpRepl.Tests/Commands/EchoCommandTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public async Task PostCommand_WithEchoOn_OnlyPrintsRequestBodyOnce()
out IPreferences preferences);
httpState.EchoRequest = true;

PostCommand postCommand = new PostCommand(fileSystem, preferences);
PostCommand postCommand = new PostCommand(fileSystem, preferences, new NullTelemetry());
await postCommand.ExecuteAsync(shellState, httpState, parseResult, CancellationToken.None);

List<string> result = shellState.Output;
Expand Down
Loading