Skip to content

Commit 50de8cd

Browse files
Merge pull request #32 from OmniSharp/logging
Started logging
2 parents a7ba5aa + 809f324 commit 50de8cd

19 files changed

+320
-76
lines changed

.appveyor.yml

+4-2
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,17 @@ deploy:
2222
server: https://www.myget.org/F/omnisharp/api/v2/package
2323
api_key:
2424
secure: eoBrSWDtOXSxyUOoCSTyQCeDkvU18W67pE3w26viEUBRi1K4Tru0cTjUtDUB7l9V
25-
skip_symbols: true
25+
skip_symbols: false
26+
symbol_server: https://www.myget.org/F/omnisharp/symbols/api/v2/package
2627
artifact: /.*\.nupkg/
2728
on:
2829
branch: master
2930
- provider: NuGet
3031
server: https://www.myget.org/F/omnisharp/api/v2/package
3132
api_key:
3233
secure: eoBrSWDtOXSxyUOoCSTyQCeDkvU18W67pE3w26viEUBRi1K4Tru0cTjUtDUB7l9V
33-
skip_symbols: true
34+
skip_symbols: false
35+
symbol_server: https://www.myget.org/F/omnisharp/symbols/api/v2/package
3436
artifact: /.*\.nupkg/
3537
on:
3638
appveyor_repo_tag: true

build.cake

+1
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ Task("Pack")
132132
DotNetCorePack(project.FullPath, new DotNetCorePackSettings
133133
{
134134
NoBuild = true,
135+
IncludeSymbols = true,
135136
Configuration = configuration,
136137
EnvironmentVariables = GitVersionEnvironmentVariables,
137138
OutputDirectory = artifacts + "/nuget"

sample/SampleServer/Program.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Diagnostics;
33
using System.Threading.Tasks;
4+
using Microsoft.Extensions.Logging;
45
using OmniSharp.Extensions.LanguageServer;
56
using OmniSharp.Extensions.LanguageServer.Abstractions;
67
using OmniSharp.Extensions.LanguageServer.Capabilities.Client;
@@ -25,7 +26,7 @@ static async Task MainAsync(string[] args)
2526
// await Task.Delay(100);
2627
//}
2728

28-
var server = new LanguageServer(Console.OpenStandardInput(), Console.OpenStandardOutput());
29+
var server = new LanguageServer(Console.OpenStandardInput(), Console.OpenStandardOutput(), new LoggerFactory());
2930

3031
server.AddHandler(new TextDocumentHandler(server));
3132

sample/SampleServer/SampleServer.csproj

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
<ItemGroup>
1010
<ProjectReference Include="../../src/Lsp/Lsp.csproj" />
11+
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.0" />
1112
</ItemGroup>
1213

13-
</Project>
14+
</Project>

src/JsonRpc/Connection.cs

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.IO;
3+
using Microsoft.Extensions.Logging;
34

45
namespace OmniSharp.Extensions.JsonRpc
56
{
@@ -14,7 +15,8 @@ public Connection(
1415
IReciever reciever,
1516
IRequestProcessIdentifier requestProcessIdentifier,
1617
IRequestRouter requestRouter,
17-
IResponseRouter responseRouter)
18+
IResponseRouter responseRouter,
19+
ILoggerFactory loggerFactory)
1820
{
1921
_requestRouter = requestRouter;
2022

@@ -24,7 +26,8 @@ public Connection(
2426
reciever,
2527
requestProcessIdentifier,
2628
requestRouter,
27-
responseRouter
29+
responseRouter,
30+
loggerFactory
2831
);
2932
}
3033

src/JsonRpc/IScheduler.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@ namespace OmniSharp.Extensions.JsonRpc
66
public interface IScheduler : IDisposable
77
{
88
void Start();
9-
void Add(RequestProcessType type, Func<Task> request);
9+
void Add(RequestProcessType type, string name, Func<Task> request);
1010
}
11-
}
11+
}

src/JsonRpc/InputHandler.cs

+8-3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Threading;
55
using System.Threading.Tasks;
66
using Newtonsoft.Json.Linq;
7+
using Microsoft.Extensions.Logging;
78
using OmniSharp.Extensions.JsonRpc.Server.Messages;
89

910
namespace OmniSharp.Extensions.JsonRpc
@@ -23,6 +24,7 @@ public class InputHandler : IInputHandler
2324
private Thread _inputThread;
2425
private readonly IRequestRouter _requestRouter;
2526
private readonly IResponseRouter _responseRouter;
27+
private readonly ILogger<InputHandler> _logger;
2628
private readonly IScheduler _scheduler;
2729

2830
public InputHandler(
@@ -31,7 +33,8 @@ public InputHandler(
3133
IReciever reciever,
3234
IRequestProcessIdentifier requestProcessIdentifier,
3335
IRequestRouter requestRouter,
34-
IResponseRouter responseRouter
36+
IResponseRouter responseRouter,
37+
ILoggerFactory loggerFactory
3538
)
3639
{
3740
if (!input.CanRead) throw new ArgumentException($"must provide a readable stream for {nameof(input)}", nameof(input));
@@ -41,8 +44,8 @@ IResponseRouter responseRouter
4144
_requestProcessIdentifier = requestProcessIdentifier;
4245
_requestRouter = requestRouter;
4346
_responseRouter = responseRouter;
44-
45-
_scheduler = new ProcessScheduler();
47+
_logger = loggerFactory.CreateLogger<InputHandler>();
48+
_scheduler = new ProcessScheduler(loggerFactory);
4649
_inputThread = new Thread(ProcessInputStream) { IsBackground = true, Name = "ProcessInputStream" };
4750
}
4851

@@ -163,6 +166,7 @@ private void HandleRequest(string request)
163166
{
164167
_scheduler.Add(
165168
type,
169+
item.Request.Method,
166170
async () => {
167171
var result = await _requestRouter.RouteRequest(item.Request);
168172
_outputHandler.Send(result.Value);
@@ -173,6 +177,7 @@ private void HandleRequest(string request)
173177
{
174178
_scheduler.Add(
175179
type,
180+
item.Notification.Method,
176181
() => {
177182
_requestRouter.RouteNotification(item.Notification);
178183
return Task.CompletedTask;

src/JsonRpc/JsonRpc.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
<ItemGroup>
99
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
1010
<PackageReference Include="System.ValueTuple" Version="4.4.0" />
11+
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="1.0.2" />
1112
</ItemGroup>
1213
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.6' ">
1314
<PackageReference Include="System.Diagnostics.Process" Version="4.3.0" />

src/JsonRpc/ProcessScheduler.cs

+36-16
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,21 @@
33
using System.Collections.Generic;
44
using System.Threading;
55
using System.Threading.Tasks;
6+
using Microsoft.Extensions.Logging;
67

78
namespace OmniSharp.Extensions.JsonRpc
89
{
910
public class ProcessScheduler : IScheduler
1011
{
11-
private readonly BlockingCollection<(RequestProcessType type, Func<Task> request)> _queue;
12+
private readonly ILogger<ProcessScheduler> _logger;
13+
private readonly BlockingCollection<(RequestProcessType type, string name, Func<Task> request)> _queue;
1214
private readonly CancellationTokenSource _cancel;
1315
private readonly Thread _thread;
1416

15-
public ProcessScheduler()
17+
public ProcessScheduler(ILoggerFactory loggerFactory)
1618
{
17-
_queue = new BlockingCollection<(RequestProcessType type, Func<Task> request)>();
19+
_logger = loggerFactory.CreateLogger<ProcessScheduler>();
20+
_queue = new BlockingCollection<(RequestProcessType type, string name, Func<Task> request)>();
1821
_cancel = new CancellationTokenSource();
1922
_thread = new Thread(ProcessRequestQueue) { IsBackground = true, Name = "ProcessRequestQueue" };
2023
}
@@ -24,9 +27,9 @@ public void Start()
2427
_thread.Start();
2528
}
2629

27-
public void Add(RequestProcessType type, Func<Task> request)
30+
public void Add(RequestProcessType type, string name, Func<Task> request)
2831
{
29-
_queue.Add((type, request));
32+
_queue.Add((type, name, request));
3033
}
3134

3235
private Task Start(Func<Task> request)
@@ -42,7 +45,7 @@ private List<Task> RemoveCompleteTasks(List<Task> list)
4245
if (list.Count == 0) return list;
4346

4447
var result = new List<Task>();
45-
foreach(var t in list)
48+
foreach (var t in list)
4649
{
4750
if (t.IsFaulted)
4851
{
@@ -69,20 +72,32 @@ private void ProcessRequestQueue()
6972
{
7073
if (_queue.TryTake(out var item, Timeout.Infinite, token))
7174
{
72-
var (type, request) = item;
73-
if (type == RequestProcessType.Serial)
75+
var (type, name, request) = item;
76+
try
7477
{
75-
Task.WaitAll(waitables.ToArray(), token);
76-
Start(request).Wait(token);
78+
if (type == RequestProcessType.Serial)
79+
{
80+
Task.WaitAll(waitables.ToArray(), token);
81+
Start(request).Wait(token);
82+
}
83+
else if (type == RequestProcessType.Parallel)
84+
{
85+
waitables.Add(Start(request));
86+
}
87+
else
88+
throw new NotImplementedException("Only Serial and Parallel execution types can be handled currently");
89+
waitables = RemoveCompleteTasks(waitables);
90+
Interlocked.Exchange(ref _TestOnly_NonCompleteTaskCount, waitables.Count);
7791
}
78-
else if (type == RequestProcessType.Parallel)
92+
catch (OperationCanceledException ex) when (ex.CancellationToken == token)
7993
{
80-
waitables.Add(Start(request));
94+
throw;
95+
}
96+
catch (Exception e)
97+
{
98+
// TODO: Create proper event ids
99+
_logger.LogCritical(Events.UnhandledRequest, e, "Unhandled exception executing request {Name}", name);
81100
}
82-
else
83-
throw new NotImplementedException("Only Serial and Parallel execution types can be handled currently");
84-
waitables = RemoveCompleteTasks(waitables);
85-
Interlocked.Exchange(ref _TestOnly_NonCompleteTaskCount, waitables.Count);
86101
}
87102
}
88103
}
@@ -112,4 +127,9 @@ public void Dispose()
112127
_cancel.Dispose();
113128
}
114129
}
130+
131+
static class Events
132+
{
133+
public static EventId UnhandledRequest = new EventId(1337_100);
134+
}
115135
}

src/Lsp/ILanguageServer.cs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23
using OmniSharp.Extensions.JsonRpc;
34
using OmniSharp.Extensions.LanguageServer.Models;
45

@@ -7,8 +8,10 @@ namespace OmniSharp.Extensions.LanguageServer
78
public interface ILanguageServer : IResponseRouter
89
{
910
IDisposable AddHandler(IJsonRpcHandler handler);
11+
IDisposable AddHandlers(IEnumerable<IJsonRpcHandler> handlers);
12+
IDisposable AddHandlers(params IJsonRpcHandler[] handlers);
1013

1114
InitializeParams Client { get; }
1215
InitializeResult Server { get; }
1316
}
14-
}
17+
}

src/Lsp/LanguageServer.cs

+11-5
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
using OmniSharp.Extensions.LanguageServer.Handlers;
1515
using OmniSharp.Extensions.LanguageServer.Models;
1616
using OmniSharp.Extensions.LanguageServer.Protocol.Document;
17+
using Microsoft.Extensions.Logging;
1718

1819
namespace OmniSharp.Extensions.LanguageServer
1920
{
@@ -30,20 +31,25 @@ public class LanguageServer : ILanguageServer, IInitializeHandler, IInitializedH
3031
private readonly HandlerCollection _collection = new HandlerCollection();
3132
private readonly IResponseRouter _responseRouter;
3233
private readonly LspReciever _reciever;
34+
private readonly ILoggerFactory _loggerFactory;
3335
private readonly TaskCompletionSource<InitializeResult> _initializeComplete = new TaskCompletionSource<InitializeResult>();
3436
private readonly CompositeDisposable _disposable = new CompositeDisposable();
3537

36-
public LanguageServer(Stream input, Stream output)
37-
: this(input, new OutputHandler(output), new LspReciever(), new RequestProcessIdentifier())
38+
public LanguageServer(Stream input, Stream output, ILoggerFactory loggerFactory)
39+
: this(input, new OutputHandler(output), new LspReciever(), new RequestProcessIdentifier(), loggerFactory)
3840
{
3941
}
4042

41-
internal LanguageServer(Stream input, IOutputHandler output, LspReciever reciever, IRequestProcessIdentifier requestProcessIdentifier)
43+
internal LanguageServer(Stream input, IOutputHandler output, LspReciever reciever, IRequestProcessIdentifier requestProcessIdentifier, ILoggerFactory loggerFactory)
4244
{
45+
// TODO: This might not be the best
46+
loggerFactory.AddProvider(new LanguageServerLoggerProvider(this));
47+
4348
_reciever = reciever;
49+
_loggerFactory = loggerFactory;
4450
_requestRouter = new LspRequestRouter(_collection);
4551
_responseRouter = new ResponseRouter(output);
46-
_connection = new Connection(input, output, reciever, requestProcessIdentifier, _requestRouter, _responseRouter);
52+
_connection = new Connection(input, output, reciever, requestProcessIdentifier, _requestRouter, _responseRouter, loggerFactory);
4753

4854
_exitHandler = new ExitHandler(_shutdownHandler);
4955

@@ -57,7 +63,7 @@ internal LanguageServer(Stream input, IOutputHandler output, LspReciever recieve
5763

5864
public IDisposable AddHandler(IJsonRpcHandler handler)
5965
{
60-
return AddHandler(handler);
66+
return AddHandlers(handler);
6167
}
6268

6369
public IDisposable AddHandlers(IEnumerable<IJsonRpcHandler> handlers)

src/Lsp/LanguageServerLogger.cs

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
using System;
2+
using OmniSharp.Extensions.LanguageServer.Models;
3+
using Microsoft.Extensions.Logging;
4+
using OmniSharp.Extensions.LanguageServer.Protocol;
5+
6+
namespace OmniSharp.Extensions.LanguageServer
7+
{
8+
class LanguageServerLogger : ILogger
9+
{
10+
private LanguageServer _languageServer;
11+
12+
public LanguageServerLogger(LanguageServer languageServer)
13+
{
14+
_languageServer = languageServer;
15+
}
16+
17+
public IDisposable BeginScope<TState>(TState state)
18+
{
19+
// TODO
20+
return new ImmutableDisposable();
21+
}
22+
23+
public bool IsEnabled(LogLevel logLevel)
24+
{
25+
// TODO: setup as configuration somehwhere (from trace perhaps?)
26+
return true;
27+
}
28+
29+
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
30+
{
31+
if (TryGetMessageType(logLevel, out var messageType))
32+
{
33+
_languageServer.Log(new LogMessageParams()
34+
{
35+
Type = messageType,
36+
Message = formatter(state, exception)
37+
});
38+
}
39+
}
40+
41+
private bool TryGetMessageType(LogLevel logLevel, out MessageType messageType)
42+
{
43+
switch (logLevel)
44+
{
45+
case LogLevel.Critical:
46+
case LogLevel.Error:
47+
messageType = MessageType.Error;
48+
return true;
49+
case LogLevel.Warning:
50+
messageType = MessageType.Warning;
51+
return true;
52+
case LogLevel.Information:
53+
messageType = MessageType.Info;
54+
return true;
55+
case LogLevel.Debug:
56+
case LogLevel.Trace:
57+
messageType = MessageType.Info;
58+
return true;
59+
}
60+
messageType = MessageType.Log;
61+
return false;
62+
}
63+
}
64+
}

0 commit comments

Comments
 (0)