Skip to content

Commit cd67606

Browse files
authored
Add EventSource and activity tags to server (#341)
1 parent c9ffae0 commit cd67606

22 files changed

Lines changed: 718 additions & 82 deletions

examples/Server/Startup.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,8 @@
2020
using System.IdentityModel.Tokens.Jwt;
2121
using System.Security.Claims;
2222
using System.Security.Cryptography.X509Certificates;
23-
using System.Threading.Tasks;
2423
using Count;
2524
using Greet;
26-
using Microsoft.AspNetCore.Authentication.Certificate;
2725
using Microsoft.AspNetCore.Authentication.JwtBearer;
2826
using Microsoft.AspNetCore.Builder;
2927
using Microsoft.AspNetCore.Http;
@@ -44,14 +42,14 @@ public void ConfigureServices(IServiceCollection services)
4442
{
4543
// This registers a global interceptor with a Singleton lifetime. The interceptor must be added to the service collection in addition to being registered here.
4644
options.Interceptors.Add<MaxConcurrentCallsInterceptor>();
47-
// This registers a global interceptor with a Scoped lifetime.
48-
options.Interceptors.Add<MaxStreamingRequestTimeoutInterceptor>(TimeSpan.FromSeconds(30));
4945
})
5046
.AddServiceOptions<GreeterService>(options =>
5147
{
5248
// This registers an interceptor for the Greeter service with a Singleton lifetime.
5349
// NOTE: Not all calls should be cached. Since the response of this service only depends on the request and no other state, adding caching here is acceptable.
5450
options.Interceptors.Add<UnaryCachingInterceptor>();
51+
// This registers an interceptor for the Greeter service with a Scoped lifetime.
52+
options.Interceptors.Add<MaxStreamingRequestTimeoutInterceptor>(TimeSpan.FromSeconds(30));
5553
});
5654
services.AddGrpcReflection();
5755
services.AddSingleton(new MaxConcurrentCallsInterceptor(200));

perf/Grpc.AspNetCore.Microbenchmarks/Internal/MessageHelpers.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,10 @@ namespace Grpc.AspNetCore.Microbenchmarks.Internal
2828
{
2929
internal static class MessageHelpers
3030
{
31-
private static readonly HttpContextServerCallContext TestServerCallContext = new HttpContextServerCallContext(new DefaultHttpContext(), new GrpcServiceOptions(), NullLogger.Instance);
31+
private static readonly HttpContextServerCallContext TestServerCallContext = new HttpContextServerCallContext(
32+
new DefaultHttpContext(),
33+
new GrpcServiceOptions(),
34+
NullLogger.Instance);
3235

3336
static MessageHelpers()
3437
{

src/Grpc.AspNetCore.Server/Internal/CallHandlers/ClientStreamingServerCallHandler.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
#endregion
1818

19-
using System;
2019
using System.Threading.Tasks;
2120
using Grpc.AspNetCore.Server.Model;
2221
using Grpc.Core;
@@ -113,6 +112,8 @@ protected override async Task HandleCallAsyncCore(HttpContext httpContext, HttpC
113112

114113
var responseBodyWriter = httpContext.Response.BodyWriter;
115114
await responseBodyWriter.WriteMessageAsync(response, serverCallContext, Method.ResponseMarshaller.ContextualSerializer, canFlush: false);
115+
116+
GrpcEventSource.Log.MessageSent();
116117
}
117118
}
118119
}

src/Grpc.AspNetCore.Server/Internal/CallHandlers/DuplexStreamingServerCallHandler.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
#endregion
1818

19-
using System;
2019
using System.Threading.Tasks;
2120
using Grpc.AspNetCore.Server.Model;
2221
using Grpc.Core;

src/Grpc.AspNetCore.Server/Internal/CallHandlers/ServerCallHandlerBase.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,16 @@
2525

2626
namespace Grpc.AspNetCore.Server.Internal.CallHandlers
2727
{
28-
internal abstract class ServerCallHandlerBase<TService, TRequest, TResponse> : IServerCallHandler
28+
internal abstract class ServerCallHandlerBase<TService, TRequest, TResponse>
2929
{
3030
protected Method<TRequest, TResponse> Method { get; }
3131
protected GrpcServiceOptions ServiceOptions { get; }
3232
protected ILogger Logger { get; }
3333

34-
protected ServerCallHandlerBase(Method<TRequest, TResponse> method, GrpcServiceOptions serviceOptions, ILoggerFactory loggerFactory)
34+
protected ServerCallHandlerBase(
35+
Method<TRequest, TResponse> method,
36+
GrpcServiceOptions serviceOptions,
37+
ILoggerFactory loggerFactory)
3538
{
3639
Method = method;
3740
ServiceOptions = serviceOptions;

src/Grpc.AspNetCore.Server/Internal/CallHandlers/ServerStreamingServerCallHandler.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
#endregion
1818

19-
using System;
2019
using System.Threading.Tasks;
2120
using Grpc.AspNetCore.Server.Model;
2221
using Grpc.Core;
@@ -77,6 +76,8 @@ protected override async Task HandleCallAsyncCore(HttpContext httpContext, HttpC
7776
var request = Method.RequestMarshaller.ContextualDeserializer(serverCallContext.DeserializationContext);
7877
serverCallContext.DeserializationContext.SetPayload(null);
7978

79+
GrpcEventSource.Log.MessageReceived();
80+
8081
if (_pipelineInvoker == null)
8182
{
8283
var activator = httpContext.RequestServices.GetRequiredService<IGrpcServiceActivator<TService>>();

src/Grpc.AspNetCore.Server/Internal/CallHandlers/UnaryServerCallHandler.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
#endregion
1818

19-
using System;
2019
using System.Threading.Tasks;
2120
using Grpc.AspNetCore.Server.Model;
2221
using Grpc.Core;
@@ -76,6 +75,8 @@ protected override async Task HandleCallAsyncCore(HttpContext httpContext, HttpC
7675
var request = Method.RequestMarshaller.ContextualDeserializer(serverCallContext.DeserializationContext);
7776
serverCallContext.DeserializationContext.SetPayload(null);
7877

78+
GrpcEventSource.Log.MessageReceived();
79+
7980
TResponse? response = null;
8081

8182
if (_pipelineInvoker == null)
@@ -108,6 +109,8 @@ protected override async Task HandleCallAsyncCore(HttpContext httpContext, HttpC
108109

109110
var responseBodyWriter = httpContext.Response.BodyWriter;
110111
await responseBodyWriter.WriteMessageAsync(response, serverCallContext, Method.ResponseMarshaller.ContextualSerializer, canFlush: false);
112+
113+
GrpcEventSource.Log.MessageSent();
111114
}
112115
}
113116
}
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
#region Copyright notice and license
2+
3+
// Copyright 2019 The gRPC Authors
4+
//
5+
// Licensed under the Apache License, Version 2.0 (the "License");
6+
// you may not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
17+
#endregion
18+
19+
using System.Diagnostics.Tracing;
20+
using System.Runtime.CompilerServices;
21+
using System.Threading;
22+
using Grpc.Core;
23+
24+
namespace Grpc.AspNetCore.Server.Internal
25+
{
26+
internal class GrpcEventSource : EventSource
27+
{
28+
public static readonly GrpcEventSource Log = new GrpcEventSource();
29+
30+
private PollingCounter? _totalCallsCounter;
31+
private PollingCounter? _currentCallsCounter;
32+
private PollingCounter? _messagesSentCounter;
33+
private PollingCounter? _messagesReceivedCounter;
34+
private PollingCounter? _callsFailedCounter;
35+
private PollingCounter? _callsDeadlineExceededCounter;
36+
private PollingCounter? _callsUnimplementedCounter;
37+
38+
private long _totalCalls;
39+
private long _currentCalls;
40+
private long _messageSent;
41+
private long _messageReceived;
42+
private long _callsFailed;
43+
private long _callsDeadlineExceeded;
44+
private long _callsUnimplemented;
45+
46+
internal GrpcEventSource()
47+
: base("Grpc.AspNetCore.Server")
48+
{
49+
}
50+
51+
// Used for testing
52+
internal GrpcEventSource(string eventSourceName)
53+
: base(eventSourceName)
54+
{
55+
}
56+
57+
[MethodImpl(MethodImplOptions.NoInlining)]
58+
[Event(eventId: 1, Level = EventLevel.Verbose)]
59+
public void CallStart(string method)
60+
{
61+
Interlocked.Increment(ref _totalCalls);
62+
Interlocked.Increment(ref _currentCalls);
63+
64+
WriteEvent(1, method);
65+
}
66+
67+
[MethodImpl(MethodImplOptions.NoInlining)]
68+
[Event(eventId: 2, Level = EventLevel.Verbose)]
69+
public void CallStop()
70+
{
71+
Interlocked.Decrement(ref _currentCalls);
72+
73+
WriteEvent(2);
74+
}
75+
76+
[MethodImpl(MethodImplOptions.NoInlining)]
77+
[Event(eventId: 3, Level = EventLevel.Error)]
78+
public void CallFailed(StatusCode statusCode)
79+
{
80+
Interlocked.Increment(ref _callsFailed);
81+
82+
WriteEvent(3, (int)statusCode);
83+
}
84+
85+
[MethodImpl(MethodImplOptions.NoInlining)]
86+
[Event(eventId: 4, Level = EventLevel.Error)]
87+
public void CallDeadlineExceeded()
88+
{
89+
Interlocked.Increment(ref _callsDeadlineExceeded);
90+
91+
WriteEvent(4);
92+
}
93+
94+
[MethodImpl(MethodImplOptions.NoInlining)]
95+
[Event(eventId: 5, Level = EventLevel.Verbose)]
96+
public void MessageSent()
97+
{
98+
Interlocked.Increment(ref _messageSent);
99+
100+
WriteEvent(5);
101+
}
102+
103+
[MethodImpl(MethodImplOptions.NoInlining)]
104+
[Event(eventId: 6, Level = EventLevel.Verbose)]
105+
public void MessageReceived()
106+
{
107+
Interlocked.Increment(ref _messageReceived);
108+
109+
WriteEvent(6);
110+
}
111+
112+
[MethodImpl(MethodImplOptions.NoInlining)]
113+
[Event(eventId: 7, Level = EventLevel.Verbose)]
114+
public void CallUnimplemented(string method)
115+
{
116+
Interlocked.Increment(ref _callsUnimplemented);
117+
118+
WriteEvent(7, method);
119+
}
120+
121+
protected override void OnEventCommand(EventCommandEventArgs command)
122+
{
123+
if (command.Command == EventCommand.Enable)
124+
{
125+
// This is the convention for initializing counters in the RuntimeEventSource (lazily on the first enable command).
126+
// They aren't disabled afterwards...
127+
128+
_totalCallsCounter ??= new PollingCounter("total-calls", this, () => _totalCalls)
129+
{
130+
DisplayName = "Total Calls",
131+
};
132+
_currentCallsCounter ??= new PollingCounter("current-calls", this, () => _currentCalls)
133+
{
134+
DisplayName = "Current Calls"
135+
};
136+
_callsFailedCounter ??= new PollingCounter("calls-failed", this, () => _callsFailed)
137+
{
138+
DisplayName = "Total Calls Failed",
139+
};
140+
_callsDeadlineExceededCounter ??= new PollingCounter("calls-deadline-exceeded", this, () => _callsDeadlineExceeded)
141+
{
142+
DisplayName = "Total Calls Deadline Exceeded",
143+
};
144+
_messagesSentCounter ??= new PollingCounter("messages-sent", this, () => _messageSent)
145+
{
146+
DisplayName = "Total Messages Sent",
147+
};
148+
_messagesReceivedCounter ??= new PollingCounter("messages-received", this, () => _messageReceived)
149+
{
150+
DisplayName = "Total Messages Received",
151+
};
152+
_callsUnimplementedCounter ??= new PollingCounter("calls-unimplemented", this, () => _callsUnimplemented)
153+
{
154+
DisplayName = "Total Calls Unimplemented",
155+
};
156+
}
157+
}
158+
}
159+
}

src/Grpc.AspNetCore.Server/Internal/IServerCallHandler.cs renamed to src/Grpc.AspNetCore.Server/Internal/GrpcServerConstants.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-

2-
#region Copyright notice and license
1+
#region Copyright notice and license
32

43
// Copyright 2019 The gRPC Authors
54
//
@@ -17,13 +16,14 @@
1716

1817
#endregion
1918

20-
using System.Threading.Tasks;
21-
using Microsoft.AspNetCore.Http;
22-
2319
namespace Grpc.AspNetCore.Server.Internal
2420
{
25-
internal interface IServerCallHandler
21+
internal static class GrpcServerConstants
2622
{
27-
Task HandleCallAsync(HttpContext httpContext);
23+
internal const string HostActivityName = "Microsoft.AspNetCore.Hosting.HttpRequestIn";
24+
internal const string HostActivityChanged = HostActivityName + ".Changed";
25+
26+
internal const string ActivityStatusCodeTag = "grpc.status_code";
27+
internal const string ActivityMethodTag = "grpc.method";
2828
}
2929
}

0 commit comments

Comments
 (0)