-
Notifications
You must be signed in to change notification settings - Fork 762
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
Initial changes to add telemetry #2774
Conversation
ce2dd5d
to
dfe4d43
Compare
"command": "bicep.Telemetry", | ||
"arguments": [ | ||
{ | ||
"EventName": "TopLevelDeclarationSnippetInsertion", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Rather long telemetry event name. Consider shortening?
Is it possible that later snippet insertions would not be top-level or declaration? I.e. SnippetInsertion not good enough?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We want to add telemetry for resource and module body snippet insertions as well. We could also do something like - SnippetInsertion/TopLevel
SnippetInsertion/ResourceBody
SnippetInsertion/ModuleBody
I think it would show up as vscode-bicep/SnippetInsertion/TopLevel
@MarcusFelling , do you have any suggestions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a big deal, you just have to deal with whatever names you end up with in queries.
Dictionary<string, string> properties = new Dictionary<string, string>() | ||
{ | ||
{ "name", resourceSnippet.Prefix } | ||
}; | ||
TelemetryEvent telemetryEvent = new(TelemetryConstants.EventNames.TopLevelDeclarationSnippetInsertion, properties); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be worth creating a static method to set the properties, rather than exposing the constructor - that way as we add telemetry events, they're all contained in one place, and enforcing more control over the structure of the dictionary?
Thinking something like:
var telemetryEvent = TelemetryEvent.CreateTopLevelDeclarationSnippetInsertion(name: resourceSnippet.Prefix)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@anthony-c-martin, I refactored this class a bit. Let me know what you think:
5078ab9
|
||
namespace Bicep.LanguageServer.Handlers | ||
{ | ||
public class BicepTelemetryHandler : ExecuteCommandHandler |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you should be able to extend ExecuteCommandHandlerBase<TelemetryEvent>
instead of ExecuteCommandHandler
and avoid having to write your own deserialization logic in the Handle
method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated here:
ffbef4c
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With omnisharp 19, looks like the base handler doesn't take in a ISerializer. So added back the deserialization logic. Let me know if I am missing something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated the base class here:
62d6763
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a few comments, please take a look!
e4dd5cb
to
9ab7544
Compare
9ab7544
to
6de1c07
Compare
@@ -67,24 +67,6 @@ | |||
"newText": "if (${1:condition}) {\n\t$0\n}" | |||
} | |||
}, | |||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is expected. There was a bug in SnippetsProvider. See corresponding change in SnippetsProvider.cs.
// Flow of events: | ||
// 1. workspace/executeCommand request is sent from the client to the server | ||
// 2. The above triggers telemetry/event from server to client | ||
public class BicepTelemetryHandler : ExecuteCommandHandlerBase<BicepTelemetryEvent> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like the base class has been renamed:
https://github.com/OmniSharp/csharp-language-server-protocol/blob/1b6788df2600083c28811913a221ccac7b1d72c9/src/Protocol/Features/Workspace/ExecuteCommandFeature.cs#L118-L141
I still think it's worth using this rather than doing it ourselves, as that way you ensure that the exact same serializer is being used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated here:
62d6763
Thank you!
@@ -10,8 +10,8 @@ | |||
|
|||
namespace Bicep.Core { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a generated file - please could you revert the changes to it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reverted all, but one change in ln 1. Not sure why it's complaining. VS IDE does some auto formatting. I tried copying it from a clean machine, still has a diff in ln 1
extensionData["eventName"].ToString().Should().Be(TelemetryConstants.EventNames.TopLevelDeclarationSnippetInsertion); | ||
extensionData["properties"].ToString().Should().BeEquivalentToIgnoringNewlines(@"{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nit] we have JToken assertions - you should be able to use:
extensionData["eventName"].Should().DeepEqual(TelemetryConstants.EventNames.TopLevelDeclarationSnippetInsertion);
extensionData["properties"].Should().DeepEqual(new JObject {
["name"] = "res-aks-cluster",
});
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't need this anymore. Cleaned up here:
62d6763
TestContext, | ||
options => | ||
{ | ||
options.OnTelemetryEvent(telemetry => telemetryReceived.SetResult(telemetry)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can use the typed handler here to avoid the dictionary serialization that TelemetryEventParams
does:
options.OnTelemetryEvent<BicepTelemetryEvent>(telemetry => telemetryReceived.SetResult(telemetry));
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated here:
62d6763
await client.ResolveCompletion(completionItem); | ||
await client.Workspace.ExecuteCommand(command); | ||
|
||
return telemetryReceived; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not just return the data directly to avoid repetition:
await IntegrationTestHelper.WithTimeoutAsync(telemetryReceived.Task);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated here:
62d6763
Command? command = completionItem.Command; | ||
|
||
command!.Name.Should().Be(TelemetryConstants.CommandName); | ||
|
||
JArray? arguments = command!.Arguments; | ||
BicepTelemetryEvent? telemetryEvent = arguments!.First().ToObject<BicepTelemetryEvent>(); | ||
|
||
telemetryEvent!.EventName.Should().Be(eventName); | ||
telemetryEvent!.Properties!.Should().Equal(properties); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can remove all of these assertions about the command, as you're validating them all at the very end - ultimately that's what matters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated here:
62d6763
|
||
public string? EventName { get; set; } | ||
|
||
public static BicepTelemetryEvent Create(string eventName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't explain myself well with the suggestion of implementing Create
- what I was thinking was implementing a set of Create
methods - e.g. something like:
public record BicepTelemetryEvent : TelemetryEventParams
{
public string? EventName { get; set; }
public Dictionary<string, string>? Properties { get; set; }
public static BicepTelemetryEvent CreateTopLevelDeclarationSnippetInsertion(string name)
=> new BicepTelemetryEvent {
EventName = TelemetryConstants.EventNames.TopLevelDeclarationSnippetInsertion,
Properties = new() {
["name"] = name,
},
};
public static BicepTelemetryEvent CreateResourceBodySnippetInsertion(string name, string type)
=> new BicepTelemetryEvent {
EventName = TelemetryConstants.EventNames.ResourceBodySnippetInsertion,
Properties = new() {
["name"] = name,
["type"] = type,
},
};
public static BicepTelemetryEvent CreateModuleBodySnippetInsertion(string name)
=> new BicepTelemetryEvent {
EventName = TelemetryConstants.EventNames.ModuleBodySnippetInsertion,
Properties = new() {
["name"] = name,
},
};
}
This has the benefit of grouping all the telemetry 'schemas' in one place, and simplifies the telemetry raising code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is definitely cleaner. Thanks! Updated here:
62d6763
@@ -1,4 +1,4 @@ | |||
//------------------------------------------------------------------------------ | |||
//------------------------------------------------------------------------------ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reverted all but this change. Not sure why it's complaining here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great!
Changes include: