OmniSharp / csharp-language-server-protocol

Language Server Protocol in C#
MIT License
523 stars 104 forks source link

[info request] traceparent and general logging question #549

Open ToddGrun opened 3 years ago

ToddGrun commented 3 years ago

I've got a question about logging in O#. For context, I work on the Visual Studio web tooling team, and we are using O# for html and css language server support in VS. We run the language server in it's own process as opposed to running inside the VS process. Everything works pretty dandy so far. Kudos to the work you’ve done!

To clarify what I'm trying to do, I've called ConfigureLogging and added my ILoggerProvider to the builder.Services instead of using AddLanguageProtocolLogging. My ILoggerProvider doesn't send out a window/logMessage notification, but rather writes out to a .svclog file (via LogHub) that will be able to be collected by VS and opened with other log files from the VS process which can link the activity IDs.

The difficulty I’m experiencing is trying to get logging inside this process to understand the "traceparent" activity id that VS sends over in the json payload. In VS, setting TraceSource.ActivityID is handled by this code in StreamJsonRpc, which makes it so we can associate activity ids from the two processes. However, it appears O# has it’s own RPC infrastructure, and doesn’t handle this on our behalf. I then tried looking into whether there were any hooks that I could use to inspect the JToken during the routing and gather this information before it’s converted into the appropriate args, but I haven’t been able to find any.

I’m hoping I’m misunderstanding logging inside O# and there is a way to have it understand the trace parent activity id from the client process. Any suggestions would be greatly appreciated!

NTaylorMullen commented 3 years ago

@david-driscoll this would definitely be nice! Of course if we could utilize StreamJsonRpc in O# that would also suffice. That being said I don't know the initial motivators you had when writing the original O# infrastructure. I guess the answer was probably it seemed too "VS like" lol, aka the name of the repo containing "vs" https://github.com/microsoft/vs-streamjsonrpc.

@AArnott out of sheer curiosity is StreamJsonRpc really VS intrinsic?

TanayParikh commented 3 years ago

Thanks Todd for providing those details. The Razor Language Server in VS has a similar architecture and would greatly benefit from being able to access the activity ID. Here is how we currently do it with StreamJsonRpc. Any suggestions would be appreciated! 😄

AArnott commented 3 years ago

StreamJsonRpc is decidedly not VS-specific. It's used in many dozens of apps that I've heard of, and probably many more that I haven't. We test it on Mac and Linux as well as Windows, and on .NET Core, .NET Framework and mono too. Use within O# should certainly work. If it doesn't, I'd entertain bug reports.

david-driscoll commented 3 years ago

Moving to StreamJsonRpc would be a breaking change. I'm not specifically against it, I just haven't prototyped what it would take to migrate over to it.

However I think activity support can be added fairly easily, I'll have to take a look at what's required.

david-driscoll commented 3 years ago

@NTaylorMullen honestly when I originally started the library years ago I couldn't find any other jsonrpc libraries that would do what I needed. It was built sheerly out of necessity at the time.

david-driscoll commented 3 years ago

Alright this is my first stab at getting it setup, shameless stealing (but referencing!) the work of vs-streamjsonrpc for the initial bit. I need to add unit tests and configuration code. https://github.com/OmniSharp/csharp-language-server-protocol/pull/553

david-driscoll commented 3 years ago

@AArnott Question, would supporting ContentModified work with vs-streamjsonrpc? That's the only thing I can see (on the surface anyway) that might cause me a headache to move over.

AArnott commented 3 years ago

@david-driscoll I'm not sure I understand the question. By ContentModified are you referring to the HTTP header? What would it do in the context of JSON-RPC? Is there a spec for it somewhere?

That's the only thing I can see (on the surface anyway) that might cause me a headache to move over.

Does this mean you're considering switching to StreamJsonRpc?

david-driscoll commented 3 years ago

@AArnott Yes, if it means less work for me :)

So basically the LSP spec defines an extension to the spec.

if a server detects an internal state change (for example a project context changed) that invalidates the result of a request in execution the server can error these requests with ContentModified. If clients receive a ContentModified error, it generally should not show it in the UI for the end-user. Clients can resend the request if they know how to do so. It should be noted that for all position based requests it might be especially hard for clients to re-craft a request.

In our case we use so that when we receive a text change, we can cancel any pending requests (like completion, code lens, etc). This allows us to get around to serving the subsequent requests from the client faster.

Things that I've implemented that technically outside the spec or ambiguous in the spec are...

AArnott commented 3 years ago

Your server would presumably need to record some state so that when a sequential request comes in that modifies content, any parallel request can notice that and throw your ContentModified error, but that shouldn't be too hard I think.

ToddGrun commented 3 years ago

Any update on whether consuming StreamJsonRpc is a possibility moving forward?