diff --git a/sample/SkyApm.Sample.AspNet/skyapm.json b/sample/SkyApm.Sample.AspNet/skyapm.json index d419a6950b2acb4c69ea9980237882d7ee9a1b1e..2bf0401c31316503ed95b8ac6e8f4663b1b513e8 100644 --- a/sample/SkyApm.Sample.AspNet/skyapm.json +++ b/sample/SkyApm.Sample.AspNet/skyapm.json @@ -19,7 +19,7 @@ "QueueSize": 30000, "BatchSize": 3000, "gRPC": { - "Servers": "localhost:11800", + "Servers": "172.17.168.234:11800", "Timeout": 10000, "ConnectTimeout": 10000, "ReportTimeout": 600000 diff --git a/sample/SkyApm.Sample.Backend/Controllers/GrpcController.cs b/sample/SkyApm.Sample.Backend/Controllers/GrpcController.cs new file mode 100644 index 0000000000000000000000000000000000000000..cc526d482c58d3daea21ce560a7bef4f9a2224bf --- /dev/null +++ b/sample/SkyApm.Sample.Backend/Controllers/GrpcController.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using SkyApm.Sample.Backend.Services; + +namespace SkyApm.Sample.Backend.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class GrpcController : ControllerBase + { + private readonly GreeterGrpcService _greeter; + + public GrpcController(GreeterGrpcService greeter) + { + _greeter = greeter; + } + + // GET api/values + [HttpGet] + public IEnumerable Get() + { + return new List { "value1", "value2" }; + } + + [HttpGet("greeter")] + public async Task SayHelloAsync(string name) + { + var reply = await _greeter.SayHelloAsync(name); + return Ok($"from backend grpc message{reply}"); + } + } +} \ No newline at end of file diff --git a/sample/SkyApm.Sample.Backend/Properties/launchSettings.json b/sample/SkyApm.Sample.Backend/Properties/launchSettings.json index 79617f3c605c1dc2971b640672ad86f71872fa3d..2fb7ff6ed16e1b40c0ecbce2712c9cc908f142da 100644 --- a/sample/SkyApm.Sample.Backend/Properties/launchSettings.json +++ b/sample/SkyApm.Sample.Backend/Properties/launchSettings.json @@ -18,7 +18,6 @@ }, "SkyWalking.Sample.Backend": { "commandName": "Project", - "launchBrowser": true, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development", "ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "SkyAPM.Agent.AspNetCore" diff --git a/sample/SkyApm.Sample.Backend/Services/GreeterGrpcService.cs b/sample/SkyApm.Sample.Backend/Services/GreeterGrpcService.cs new file mode 100644 index 0000000000000000000000000000000000000000..7a1cc07abebc8783ed7cc4918a595c17241f73e7 --- /dev/null +++ b/sample/SkyApm.Sample.Backend/Services/GreeterGrpcService.cs @@ -0,0 +1,51 @@ +using Grpc.Core; +using Grpc.Core.Interceptors; +using GrpcGreeter; +using SkyApm.Diagnostics.Grpc.Client; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace SkyApm.Sample.Backend.Services +{ + public class GreeterGrpcService + { + private readonly Greeter.GreeterClient _client; + public GreeterGrpcService(ClientDiagnosticInterceptor interceptor) + { + _client = new Greeter.GreeterClient(GetChannel(interceptor)); + } + + private CallInvoker GetChannel(ClientDiagnosticInterceptor interceptor) + { + var channel = new Channel("localhost:12345", ChannelCredentials.Insecure); + var invoker = channel.Intercept(interceptor); + return invoker; + } + + public string SayHello(string name) + { + var reply = _client.SayHello(new HelloRequest { Name = name }); + return reply.Message; + } + + public async Task SayHelloAsync(string name) + { + var reply = await _client.SayHelloAsync(new HelloRequest { Name = name }); + return reply.Message; + } + + public string SayHelloWithException(string name) + { + var reply = _client.SayHelloWithException(new HelloRequest { Name = name }); + return reply.Message; + } + + public async Task SayHelloWithExceptionAsync(string name) + { + var reply = await _client.SayHelloWithExceptionAsync(new HelloRequest { Name = name }); + return reply.Message; + } + } +} diff --git a/sample/SkyApm.Sample.Backend/SkyApm.Sample.Backend.csproj b/sample/SkyApm.Sample.Backend/SkyApm.Sample.Backend.csproj index 5ece6313db8c0ceb756f417c7fe972af4ba10f62..1e52143be7eb193b15ed38e3b1e9c8f9b144db4f 100644 --- a/sample/SkyApm.Sample.Backend/SkyApm.Sample.Backend.csproj +++ b/sample/SkyApm.Sample.Backend/SkyApm.Sample.Backend.csproj @@ -8,13 +8,14 @@ + 2.1.0 - + diff --git a/sample/SkyApm.Sample.Backend/Startup.cs b/sample/SkyApm.Sample.Backend/Startup.cs index 954bb39fc447b20d528bc3656d2466afd43d85f6..5395dd57ae390c7d91194b2b6b8aec55179a5c7a 100644 --- a/sample/SkyApm.Sample.Backend/Startup.cs +++ b/sample/SkyApm.Sample.Backend/Startup.cs @@ -8,6 +8,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using SkyApm.Sample.Backend.Models; using SkyApm.Sample.Backend.Sampling; +using SkyApm.Sample.Backend.Services; using SkyApm.Tracing; namespace SkyApm.Sample.Backend @@ -31,6 +32,9 @@ namespace SkyApm.Sample.Backend services.AddEntityFrameworkSqlite().AddDbContext(c => c.UseSqlite(sqliteConnection)); services.AddSingleton(); + + // DI grpc service + services.AddSingleton(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. diff --git a/sample/SkyApm.Sample.Backend/skyapm.json b/sample/SkyApm.Sample.Backend/skyapm.json index b5d2b9883d3c6a8033c7b1a912dfb993cc9985ac..2bb2afbdf86a24b2e18d9e18cf0027151a6961da 100644 --- a/sample/SkyApm.Sample.Backend/skyapm.json +++ b/sample/SkyApm.Sample.Backend/skyapm.json @@ -19,7 +19,7 @@ "QueueSize": 30000, "BatchSize": 3000, "gRPC": { - "Servers": "localhost:11800", + "Servers": "172.17.168.234:11800", "Timeout": 100000, "ConnectTimeout": 100000, "ReportTimeout": 600000 diff --git a/sample/SkyApm.Sample.Frontend/Controllers/ValuesController.cs b/sample/SkyApm.Sample.Frontend/Controllers/ValuesController.cs index e45893dc7a47f8904cc72fcb13d39e537c0d17e2..78d90cd72eb48c92a798da3e95298dde695fb9da 100644 --- a/sample/SkyApm.Sample.Frontend/Controllers/ValuesController.cs +++ b/sample/SkyApm.Sample.Frontend/Controllers/ValuesController.cs @@ -1,13 +1,22 @@ using System.Collections.Generic; using System.Net.Http; +using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; +using SkyApm.Sample.Backend.Services; namespace SkyApm.Sample.Frontend.Controllers { [Route("api/[controller]")] public class ValuesController : Controller { + private readonly GreeterGrpcService _greeter; + + public ValuesController(GreeterGrpcService greeter) + { + _greeter = greeter; + } + // GET api/values [HttpGet] public async Task> Get() @@ -25,5 +34,28 @@ namespace SkyApm.Sample.Frontend.Controllers client.GetAsync("http://localhost:5002/api/delay/200")); return await client.GetStringAsync("http://localhost:5002/api/delay/100"); } + + [HttpGet("greeter")] + public async Task SayHelloAsync(string name) + { + var content = new StringBuilder(); + var message = await _greeter.SayHelloAsync(name); + content.AppendLine($"from frontend grpc message:{message}"); + + var response = await new HttpClient().GetStringAsync("http://localhost:5002/api/values"); + content.AppendLine($"from frontend httpclient message:{response}"); + + response = await new HttpClient().GetStringAsync($"http://localhost:5002/api/grpc/greeter?name={name}"); + content.AppendLine(response); + + return Ok(content); + } + + [HttpGet("greeter/exception")] + public async Task SayHelloWithExceptionAsync(string name) + { + var message = await _greeter.SayHelloWithExceptionAsync(name); + return Ok(message); + } } } \ No newline at end of file diff --git a/sample/SkyApm.Sample.Frontend/Properties/launchSettings.json b/sample/SkyApm.Sample.Frontend/Properties/launchSettings.json index d98537c0c067b8a04fd1874518c518d86dd071d7..6c5a08f48247bb7f34c120308acbf917a7fe76b6 100644 --- a/sample/SkyApm.Sample.Frontend/Properties/launchSettings.json +++ b/sample/SkyApm.Sample.Frontend/Properties/launchSettings.json @@ -18,7 +18,6 @@ }, "SkyWalking.Sample.Frontend": { "commandName": "Project", - "launchBrowser": true, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development", "ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "SkyAPM.Agent.AspNetCore" diff --git a/sample/SkyApm.Sample.Frontend/Services/GreeterGrpcService.cs b/sample/SkyApm.Sample.Frontend/Services/GreeterGrpcService.cs new file mode 100644 index 0000000000000000000000000000000000000000..7a1cc07abebc8783ed7cc4918a595c17241f73e7 --- /dev/null +++ b/sample/SkyApm.Sample.Frontend/Services/GreeterGrpcService.cs @@ -0,0 +1,51 @@ +using Grpc.Core; +using Grpc.Core.Interceptors; +using GrpcGreeter; +using SkyApm.Diagnostics.Grpc.Client; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace SkyApm.Sample.Backend.Services +{ + public class GreeterGrpcService + { + private readonly Greeter.GreeterClient _client; + public GreeterGrpcService(ClientDiagnosticInterceptor interceptor) + { + _client = new Greeter.GreeterClient(GetChannel(interceptor)); + } + + private CallInvoker GetChannel(ClientDiagnosticInterceptor interceptor) + { + var channel = new Channel("localhost:12345", ChannelCredentials.Insecure); + var invoker = channel.Intercept(interceptor); + return invoker; + } + + public string SayHello(string name) + { + var reply = _client.SayHello(new HelloRequest { Name = name }); + return reply.Message; + } + + public async Task SayHelloAsync(string name) + { + var reply = await _client.SayHelloAsync(new HelloRequest { Name = name }); + return reply.Message; + } + + public string SayHelloWithException(string name) + { + var reply = _client.SayHelloWithException(new HelloRequest { Name = name }); + return reply.Message; + } + + public async Task SayHelloWithExceptionAsync(string name) + { + var reply = await _client.SayHelloWithExceptionAsync(new HelloRequest { Name = name }); + return reply.Message; + } + } +} diff --git a/sample/SkyApm.Sample.Frontend/SkyApm.Sample.Frontend.csproj b/sample/SkyApm.Sample.Frontend/SkyApm.Sample.Frontend.csproj index fd47fca763b55646f66ca5aa608d657e3fd20ddb..de01d8cb47a4b91da27e7326a1045361c5f5cf68 100644 --- a/sample/SkyApm.Sample.Frontend/SkyApm.Sample.Frontend.csproj +++ b/sample/SkyApm.Sample.Frontend/SkyApm.Sample.Frontend.csproj @@ -22,6 +22,7 @@ + diff --git a/sample/SkyApm.Sample.Frontend/Startup.cs b/sample/SkyApm.Sample.Frontend/Startup.cs index 3c5f65f81625fce3b4686da266d20b4e128bf491..2a6ac46e803bd142e87c1107c6ce77affed1670b 100644 --- a/sample/SkyApm.Sample.Frontend/Startup.cs +++ b/sample/SkyApm.Sample.Frontend/Startup.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using SkyApm.Sample.Backend.Services; namespace SkyApm.Sample.Frontend { @@ -18,6 +19,9 @@ namespace SkyApm.Sample.Frontend public void ConfigureServices(IServiceCollection services) { services.AddMvc(); + + // DI grpc service + services.AddSingleton(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. diff --git a/sample/SkyApm.Sample.Frontend/skyapm.json b/sample/SkyApm.Sample.Frontend/skyapm.json index 933aba8bbaabc0374c11ee7d5d416ccb4f63a511..b1b7eee38dc553570aa9f7f64d824962e8d674ee 100644 --- a/sample/SkyApm.Sample.Frontend/skyapm.json +++ b/sample/SkyApm.Sample.Frontend/skyapm.json @@ -19,9 +19,9 @@ "QueueSize": 30000, "BatchSize": 3000, "gRPC": { - "Servers": "localhost:11800", - "Timeout": 10000, - "ConnectTimeout": 10000, + "Servers": "172.17.168.234:11800", + "Timeout": 100000, + "ConnectTimeout": 100000, "ReportTimeout": 600000 } } diff --git a/sample/SkyApm.Sample.GeneralHost/skyapm.json b/sample/SkyApm.Sample.GeneralHost/skyapm.json index 29a19b8dafba457d38a581d16bb5a9baad7e94e8..10227df051f6df211956e1655134622eb5daf445 100644 --- a/sample/SkyApm.Sample.GeneralHost/skyapm.json +++ b/sample/SkyApm.Sample.GeneralHost/skyapm.json @@ -19,7 +19,7 @@ "QueueSize": 30000, "BatchSize": 3000, "gRPC": { - "Servers": "localhost:11800", + "Servers": "172.17.168.234:11800", "Timeout": 100000, "ConnectTimeout": 100000, "ReportTimeout": 600000 diff --git a/sample/grpc/SkyApm.Sample.GrpcProto/Hello.cs b/sample/grpc/SkyApm.Sample.GrpcProto/Hello.cs new file mode 100644 index 0000000000000000000000000000000000000000..2eb5d69a3440667d8da205aef90184688b5ee3a8 --- /dev/null +++ b/sample/grpc/SkyApm.Sample.GrpcProto/Hello.cs @@ -0,0 +1,312 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: hello.proto +// +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +namespace GrpcGreeter { + + /// Holder for reflection information generated from hello.proto + public static partial class HelloReflection { + + #region Descriptor + /// File descriptor for hello.proto + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static HelloReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "CgtoZWxsby5wcm90bxIFR3JlZXQiHAoMSGVsbG9SZXF1ZXN0EgwKBG5hbWUY", + "ASABKAkiHQoKSGVsbG9SZXBseRIPCgdtZXNzYWdlGAEgASgJMn4KB0dyZWV0", + "ZXISMgoIU2F5SGVsbG8SEy5HcmVldC5IZWxsb1JlcXVlc3QaES5HcmVldC5I", + "ZWxsb1JlcGx5Ej8KFVNheUhlbGxvV2l0aEV4Y2VwdGlvbhITLkdyZWV0Lkhl", + "bGxvUmVxdWVzdBoRLkdyZWV0LkhlbGxvUmVwbHlCDqoCC0dycGNHcmVldGVy", + "YgZwcm90bzM=")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { }, + new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::GrpcGreeter.HelloRequest), global::GrpcGreeter.HelloRequest.Parser, new[]{ "Name" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::GrpcGreeter.HelloReply), global::GrpcGreeter.HelloReply.Parser, new[]{ "Message" }, null, null, null) + })); + } + #endregion + + } + #region Messages + /// + /// The request message containing the user's name. + /// + public sealed partial class HelloRequest : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new HelloRequest()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::GrpcGreeter.HelloReflection.Descriptor.MessageTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public HelloRequest() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public HelloRequest(HelloRequest other) : this() { + name_ = other.name_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public HelloRequest Clone() { + return new HelloRequest(this); + } + + /// Field number for the "name" field. + public const int NameFieldNumber = 1; + private string name_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Name { + get { return name_; } + set { + name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as HelloRequest); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(HelloRequest other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Name != other.Name) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Name.Length != 0) hash ^= Name.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Name.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Name); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Name.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Name); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(HelloRequest other) { + if (other == null) { + return; + } + if (other.Name.Length != 0) { + Name = other.Name; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Name = input.ReadString(); + break; + } + } + } + } + + } + + /// + /// The response message containing the greetings. + /// + public sealed partial class HelloReply : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new HelloReply()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::GrpcGreeter.HelloReflection.Descriptor.MessageTypes[1]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public HelloReply() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public HelloReply(HelloReply other) : this() { + message_ = other.message_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public HelloReply Clone() { + return new HelloReply(this); + } + + /// Field number for the "message" field. + public const int MessageFieldNumber = 1; + private string message_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Message { + get { return message_; } + set { + message_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as HelloReply); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(HelloReply other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Message != other.Message) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Message.Length != 0) hash ^= Message.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Message.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Message); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Message.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Message); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(HelloReply other) { + if (other == null) { + return; + } + if (other.Message.Length != 0) { + Message = other.Message; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Message = input.ReadString(); + break; + } + } + } + } + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/sample/grpc/SkyApm.Sample.GrpcProto/HelloGrpc.cs b/sample/grpc/SkyApm.Sample.GrpcProto/HelloGrpc.cs new file mode 100644 index 0000000000000000000000000000000000000000..ee5e0b3bbd70a407c352bf52f5fc4d911c7e6d89 --- /dev/null +++ b/sample/grpc/SkyApm.Sample.GrpcProto/HelloGrpc.cs @@ -0,0 +1,174 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: hello.proto +// +#pragma warning disable 0414, 1591 +#region Designer generated code + +using grpc = global::Grpc.Core; + +namespace GrpcGreeter { + /// + /// The greeting service definition. + /// + public static partial class Greeter + { + static readonly string __ServiceName = "Greet.Greeter"; + + static readonly grpc::Marshaller __Marshaller_Greet_HelloRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::GrpcGreeter.HelloRequest.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_Greet_HelloReply = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::GrpcGreeter.HelloReply.Parser.ParseFrom); + + static readonly grpc::Method __Method_SayHello = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "SayHello", + __Marshaller_Greet_HelloRequest, + __Marshaller_Greet_HelloReply); + + static readonly grpc::Method __Method_SayHelloWithException = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "SayHelloWithException", + __Marshaller_Greet_HelloRequest, + __Marshaller_Greet_HelloReply); + + /// Service descriptor + public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor + { + get { return global::GrpcGreeter.HelloReflection.Descriptor.Services[0]; } + } + + /// Base class for server-side implementations of Greeter + [grpc::BindServiceMethod(typeof(Greeter), "BindService")] + public abstract partial class GreeterBase + { + /// + /// Sends a greeting + /// + /// The request received from the client. + /// The context of the server-side call handler being invoked. + /// The response to send back to the client (wrapped by a task). + public virtual global::System.Threading.Tasks.Task SayHello(global::GrpcGreeter.HelloRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task SayHelloWithException(global::GrpcGreeter.HelloRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + } + + /// Client for Greeter + public partial class GreeterClient : grpc::ClientBase + { + /// Creates a new client for Greeter + /// The channel to use to make remote calls. + public GreeterClient(grpc::ChannelBase channel) : base(channel) + { + } + /// Creates a new client for Greeter that uses a custom CallInvoker. + /// The callInvoker to use to make remote calls. + public GreeterClient(grpc::CallInvoker callInvoker) : base(callInvoker) + { + } + /// Protected parameterless constructor to allow creation of test doubles. + protected GreeterClient() : base() + { + } + /// Protected constructor to allow creation of configured clients. + /// The client configuration. + protected GreeterClient(ClientBaseConfiguration configuration) : base(configuration) + { + } + + /// + /// Sends a greeting + /// + /// The request to send to the server. + /// The initial metadata to send with the call. This parameter is optional. + /// An optional deadline for the call. The call will be cancelled if deadline is hit. + /// An optional token for canceling the call. + /// The response received from the server. + public virtual global::GrpcGreeter.HelloReply SayHello(global::GrpcGreeter.HelloRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return SayHello(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + /// + /// Sends a greeting + /// + /// The request to send to the server. + /// The options for the call. + /// The response received from the server. + public virtual global::GrpcGreeter.HelloReply SayHello(global::GrpcGreeter.HelloRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_SayHello, null, options, request); + } + /// + /// Sends a greeting + /// + /// The request to send to the server. + /// The initial metadata to send with the call. This parameter is optional. + /// An optional deadline for the call. The call will be cancelled if deadline is hit. + /// An optional token for canceling the call. + /// The call object. + public virtual grpc::AsyncUnaryCall SayHelloAsync(global::GrpcGreeter.HelloRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return SayHelloAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + /// + /// Sends a greeting + /// + /// The request to send to the server. + /// The options for the call. + /// The call object. + public virtual grpc::AsyncUnaryCall SayHelloAsync(global::GrpcGreeter.HelloRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_SayHello, null, options, request); + } + public virtual global::GrpcGreeter.HelloReply SayHelloWithException(global::GrpcGreeter.HelloRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return SayHelloWithException(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::GrpcGreeter.HelloReply SayHelloWithException(global::GrpcGreeter.HelloRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_SayHelloWithException, null, options, request); + } + public virtual grpc::AsyncUnaryCall SayHelloWithExceptionAsync(global::GrpcGreeter.HelloRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return SayHelloWithExceptionAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall SayHelloWithExceptionAsync(global::GrpcGreeter.HelloRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_SayHelloWithException, null, options, request); + } + /// Creates a new instance of client from given ClientBaseConfiguration. + protected override GreeterClient NewInstance(ClientBaseConfiguration configuration) + { + return new GreeterClient(configuration); + } + } + + /// Creates service definition that can be registered with a server + /// An object implementing the server-side handling logic. + public static grpc::ServerServiceDefinition BindService(GreeterBase serviceImpl) + { + return grpc::ServerServiceDefinition.CreateBuilder() + .AddMethod(__Method_SayHello, serviceImpl.SayHello) + .AddMethod(__Method_SayHelloWithException, serviceImpl.SayHelloWithException).Build(); + } + + /// Register service method with a service binder with or without implementation. Useful when customizing the service binding logic. + /// Note: this method is part of an experimental API that can change or be removed without any prior notice. + /// Service methods will be bound by calling AddMethod on this object. + /// An object implementing the server-side handling logic. + public static void BindService(grpc::ServiceBinderBase serviceBinder, GreeterBase serviceImpl) + { + serviceBinder.AddMethod(__Method_SayHello, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.SayHello)); + serviceBinder.AddMethod(__Method_SayHelloWithException, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.SayHelloWithException)); + } + + } +} +#endregion diff --git a/sample/grpc/SkyApm.Sample.GrpcProto/SkyApm.Sample.GrpcProto.csproj b/sample/grpc/SkyApm.Sample.GrpcProto/SkyApm.Sample.GrpcProto.csproj new file mode 100644 index 0000000000000000000000000000000000000000..30ed4c17f885fa764314eefe2806a492bf5b7fbd --- /dev/null +++ b/sample/grpc/SkyApm.Sample.GrpcProto/SkyApm.Sample.GrpcProto.csproj @@ -0,0 +1,21 @@ + + + + netstandard2.0 + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/sample/grpc/SkyApm.Sample.GrpcProto/grpc_csharp_plugin.exe b/sample/grpc/SkyApm.Sample.GrpcProto/grpc_csharp_plugin.exe new file mode 100644 index 0000000000000000000000000000000000000000..ff0faee9d2cd009b0db9086ea3e6416af5b2d12f Binary files /dev/null and b/sample/grpc/SkyApm.Sample.GrpcProto/grpc_csharp_plugin.exe differ diff --git a/sample/grpc/SkyApm.Sample.GrpcProto/proto-generate.txt b/sample/grpc/SkyApm.Sample.GrpcProto/proto-generate.txt new file mode 100644 index 0000000000000000000000000000000000000000..7d390d88ec06ea04917ac50930abca471573de47 --- /dev/null +++ b/sample/grpc/SkyApm.Sample.GrpcProto/proto-generate.txt @@ -0,0 +1 @@ +protoc.exe --proto_path protos --csharp_out=. --grpc_out=. --plugin=protoc-gen-grpc=grpc_csharp_plugin.exe hello.proto \ No newline at end of file diff --git a/sample/grpc/SkyApm.Sample.GrpcProto/protoc.exe b/sample/grpc/SkyApm.Sample.GrpcProto/protoc.exe new file mode 100644 index 0000000000000000000000000000000000000000..885ca876f80006f955853e81b50d76dd7e020e30 Binary files /dev/null and b/sample/grpc/SkyApm.Sample.GrpcProto/protoc.exe differ diff --git a/sample/grpc/SkyApm.Sample.GrpcServer/GreeterImpl.cs b/sample/grpc/SkyApm.Sample.GrpcServer/GreeterImpl.cs new file mode 100644 index 0000000000000000000000000000000000000000..f1781bfbbc10a48b3cc2f9af583d740b5059002c --- /dev/null +++ b/sample/grpc/SkyApm.Sample.GrpcServer/GreeterImpl.cs @@ -0,0 +1,28 @@ +using Grpc.Core; +using GrpcGreeter; +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; + +namespace SkyApm.Sample.GrpcServer +{ + public class GreeterImpl : Greeter.GreeterBase + { + // Server side handler of the SayHello RPC + public override async Task SayHello(HelloRequest request, ServerCallContext context) + { + await Task.Delay(150); + var httpClient = new HttpClient(); + var result = await httpClient.GetAsync("http://www.baidu.com"); + Console.WriteLine(result.Content.Headers); + return new HelloReply { Message = "Hello " + request.Name }; + } + + public override Task SayHelloWithException(HelloRequest request, ServerCallContext context) + { + throw new Exception("grpc server throw exception !!!"); + } + } +} diff --git a/sample/grpc/SkyApm.Sample.GrpcServer/Program.cs b/sample/grpc/SkyApm.Sample.GrpcServer/Program.cs new file mode 100644 index 0000000000000000000000000000000000000000..6881efa02f84a139481dfc43e52a0055bc198aed --- /dev/null +++ b/sample/grpc/SkyApm.Sample.GrpcServer/Program.cs @@ -0,0 +1,34 @@ +using Grpc.Core; +using GrpcGreeter; +using Microsoft.Extensions.Hosting; +using SkyApm.Agent.GeneralHost; +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; + +namespace SkyApm.Sample.GrpcServer +{ + class Program + { + public static async Task Main(string[] args) + { + await CreateHostBuilder(args).Build().RunAsync(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) + { + var environmentName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"); + + return new HostBuilder() + .UseEnvironment(environmentName) + .AddSkyAPM() + .ConfigureServices((hostContext, services) => + { + var startUp = new Startup(hostContext.Configuration); + var provider = startUp.ConfigureServices(services); + startUp.Use(provider); + }); + } + } +} diff --git a/sample/grpc/SkyApm.Sample.GrpcServer/Properties/launchSettings.json b/sample/grpc/SkyApm.Sample.GrpcServer/Properties/launchSettings.json new file mode 100644 index 0000000000000000000000000000000000000000..f0d7aac404bf20825eb39386707b958a43a150a2 --- /dev/null +++ b/sample/grpc/SkyApm.Sample.GrpcServer/Properties/launchSettings.json @@ -0,0 +1,10 @@ +{ + "profiles": { + "SkyApm.Sample.GrpcServer": { + "commandName": "Project", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} \ No newline at end of file diff --git a/sample/grpc/SkyApm.Sample.GrpcServer/SkyApm.Sample.GrpcServer.csproj b/sample/grpc/SkyApm.Sample.GrpcServer/SkyApm.Sample.GrpcServer.csproj new file mode 100644 index 0000000000000000000000000000000000000000..86b6737cdc5f821b72c12d23c952ec3d827a6563 --- /dev/null +++ b/sample/grpc/SkyApm.Sample.GrpcServer/SkyApm.Sample.GrpcServer.csproj @@ -0,0 +1,30 @@ + + + + Exe + netcoreapp2.2 + 7.3 + + + + + + + + + Always + PreserveNewest + + + + + + + + + + + + + + diff --git a/sample/grpc/SkyApm.Sample.GrpcServer/Startup.cs b/sample/grpc/SkyApm.Sample.GrpcServer/Startup.cs new file mode 100644 index 0000000000000000000000000000000000000000..72b820bceffdbc343589427bbbc4ce8de3f58e5e --- /dev/null +++ b/sample/grpc/SkyApm.Sample.GrpcServer/Startup.cs @@ -0,0 +1,48 @@ +using Grpc.Core; +using Grpc.Core.Interceptors; +using GrpcGreeter; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using SkyApm.Diagnostics.Grpc.Server; +using System; + +namespace SkyApm.Sample.GrpcServer +{ + public class Startup + { + public Startup(IConfiguration configuration) + { + Configuration = configuration; + } + + public IConfiguration Configuration { get; } + + public IServiceProvider ConfigureServices(IServiceCollection services) + { + services.AddLogging(); + return services.BuildServiceProvider(); + } + + public void Use(IServiceProvider provider) + { + var interceptor = provider.GetService(); + var definition = Greeter.BindService(new GreeterImpl()); + if (interceptor != null) + { + definition = definition.Intercept(interceptor); + } + int port = 12345; + Server server = new Server + { + Services = { definition }, + Ports = { new ServerPort("localhost", port, ServerCredentials.Insecure) }, + }; + server.Start(); + + Console.WriteLine("Greeter server listening on port " + port); + //Console.WriteLine("Press any key to stop the server..."); + //Console.ReadKey(); + //server.ShutdownAsync().Wait(); + } + } +} diff --git a/sample/grpc/SkyApm.Sample.GrpcServer/skyapm.json b/sample/grpc/SkyApm.Sample.GrpcServer/skyapm.json new file mode 100644 index 0000000000000000000000000000000000000000..8134dda8d7e5b5cb06b6ab2d5c43f5e5817b22b2 --- /dev/null +++ b/sample/grpc/SkyApm.Sample.GrpcServer/skyapm.json @@ -0,0 +1,29 @@ +{ + "SkyWalking": { + "ServiceName": "grpc-greeter-server", + "Namespace": "", + "HeaderVersions": [ + "sw6" + ], + "Sampling": { + "SamplePer3Secs": -1, + "Percentage": -1.0 + }, + "Logging": { + "Level": "Information", + "FilePath": "logs/skyapm-{Date}.log" + }, + "Transport": { + "Interval": 3000, + "ProtocolVersion": "v6", + "QueueSize": 30000, + "BatchSize": 3000, + "gRPC": { + "Servers": "172.17.168.234:11800", + "Timeout": 100000, + "ConnectTimeout": 100000, + "ReportTimeout": 600000 + } + } + } +} \ No newline at end of file diff --git a/skyapm-dotnet.sln b/skyapm-dotnet.sln index f9144b1e93965e6f182afaef37ee095fa4c097e9..5d26e8b64c4d644ff6c5ecbccb9241723bbefa59 100644 --- a/skyapm-dotnet.sln +++ b/skyapm-dotnet.sln @@ -92,7 +92,15 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkyApm.Benchmark", "benchma EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmark", "benchmark", "{2B7F59E8-147F-4399-9804-E7EAEF2DCB22}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SkyApm.Core.Tests", "test\SkyApm.Core.Tests\SkyApm.Core.Tests.csproj", "{5E654407-E22F-4696-A33F-C4B372F547BD}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkyApm.Core.Tests", "test\SkyApm.Core.Tests\SkyApm.Core.Tests.csproj", "{5E654407-E22F-4696-A33F-C4B372F547BD}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SkyApm.Diagnostics.Grpc", "src\SkyApm.Diagnostics.Grpc\SkyApm.Diagnostics.Grpc.csproj", "{8C389735-61CE-405C-972F-3790DF1E823E}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "grpc", "grpc", "{53E9CEBA-2D11-41FD-AA60-0151A5442CC4}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkyApm.Sample.GrpcProto", "sample\grpc\SkyApm.Sample.GrpcProto\SkyApm.Sample.GrpcProto.csproj", "{5576D9C5-8856-44AD-86AD-FE73A22751EF}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkyApm.Sample.GrpcServer", "sample\grpc\SkyApm.Sample.GrpcServer\SkyApm.Sample.GrpcServer.csproj", "{0EB6D474-A915-4075-B142-FE07321F3AA9}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -204,6 +212,18 @@ Global {5E654407-E22F-4696-A33F-C4B372F547BD}.Debug|Any CPU.Build.0 = Debug|Any CPU {5E654407-E22F-4696-A33F-C4B372F547BD}.Release|Any CPU.ActiveCfg = Release|Any CPU {5E654407-E22F-4696-A33F-C4B372F547BD}.Release|Any CPU.Build.0 = Release|Any CPU + {8C389735-61CE-405C-972F-3790DF1E823E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8C389735-61CE-405C-972F-3790DF1E823E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8C389735-61CE-405C-972F-3790DF1E823E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8C389735-61CE-405C-972F-3790DF1E823E}.Release|Any CPU.Build.0 = Release|Any CPU + {5576D9C5-8856-44AD-86AD-FE73A22751EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5576D9C5-8856-44AD-86AD-FE73A22751EF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5576D9C5-8856-44AD-86AD-FE73A22751EF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5576D9C5-8856-44AD-86AD-FE73A22751EF}.Release|Any CPU.Build.0 = Release|Any CPU + {0EB6D474-A915-4075-B142-FE07321F3AA9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0EB6D474-A915-4075-B142-FE07321F3AA9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0EB6D474-A915-4075-B142-FE07321F3AA9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0EB6D474-A915-4075-B142-FE07321F3AA9}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -243,6 +263,10 @@ Global {477D705E-576B-46C8-8F1E-9A86EDAE9D86} = {844CEACD-4C85-4B15-9E2B-892B01FDA4BB} {33581FDE-ABAF-4C27-A40A-1A2743309399} = {2B7F59E8-147F-4399-9804-E7EAEF2DCB22} {5E654407-E22F-4696-A33F-C4B372F547BD} = {613F0980-91ED-4064-8E8C-168582EF4AD7} + {8C389735-61CE-405C-972F-3790DF1E823E} = {B5E677CF-2920-4B0A-A056-E73F6B2CF2BC} + {53E9CEBA-2D11-41FD-AA60-0151A5442CC4} = {844CEACD-4C85-4B15-9E2B-892B01FDA4BB} + {5576D9C5-8856-44AD-86AD-FE73A22751EF} = {53E9CEBA-2D11-41FD-AA60-0151A5442CC4} + {0EB6D474-A915-4075-B142-FE07321F3AA9} = {53E9CEBA-2D11-41FD-AA60-0151A5442CC4} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {94C0DA2C-CCCB-4314-93A2-9809B5DD0583} diff --git a/src/SkyApm.Abstractions/Common/Components.cs b/src/SkyApm.Abstractions/Common/Components.cs index df3ba5940f3b1b0975a86390ebbebc938a6ff888..ae542a7af1d1d7c22ec242cda7383583797d7962 100644 --- a/src/SkyApm.Abstractions/Common/Components.cs +++ b/src/SkyApm.Abstractions/Common/Components.cs @@ -39,5 +39,7 @@ namespace SkyApm.Common public static readonly StringOrIntValue ASPNET = new StringOrIntValue("AspNet"); public static readonly StringOrIntValue SMART_SQL = new StringOrIntValue("SmartSql"); + + public static readonly StringOrIntValue GRPC = new StringOrIntValue("GRPC"); } } \ No newline at end of file diff --git a/src/SkyApm.Abstractions/Common/Tags.cs b/src/SkyApm.Abstractions/Common/Tags.cs index 968d322ff58a7fe6a4a7229d9cb61984e87ca66a..7b0b96916369d918d47f15b441dfe2ea68d56ef1 100644 --- a/src/SkyApm.Abstractions/Common/Tags.cs +++ b/src/SkyApm.Abstractions/Common/Tags.cs @@ -38,5 +38,9 @@ namespace SkyApm.Common public static readonly string DB_BIND_VARIABLES = "db.bind_vars"; public static readonly string MQ_TOPIC = "mq.topic"; + + public static readonly string GRPC_METHOD_NAME = "grpc.method"; + + public static readonly string GRPC_STATUS = "grpc.status"; } } \ No newline at end of file diff --git a/src/SkyApm.Agent.AspNetCore/Extensions/ServiceCollectionExtensions.cs b/src/SkyApm.Agent.AspNetCore/Extensions/ServiceCollectionExtensions.cs index adce4402397e661daceebe35d596fbe832f482e9..f6583fe4f4d4f2fa6f4c47ed307525b866fb2467 100644 --- a/src/SkyApm.Agent.AspNetCore/Extensions/ServiceCollectionExtensions.cs +++ b/src/SkyApm.Agent.AspNetCore/Extensions/ServiceCollectionExtensions.cs @@ -37,6 +37,7 @@ using SkyApm.Diagnostics.HttpClient; using SkyApm.Diagnostics.SqlClient; using SkyApm.Utilities.DependencyInjection; using SkyApm.Diagnostics.SmartSql; +using SkyApm.Diagnostics.Grpc; namespace SkyApm.Agent.AspNetCore { @@ -63,7 +64,7 @@ namespace SkyApm.Agent.AspNetCore services.AddSingleton(); services.AddSingleton(); services.AddTracing().AddSampling().AddGrpcTransport().AddLogging(); - services.AddSkyApmExtensions().AddAspNetCoreHosting().AddHttpClient().AddSqlClient() + services.AddSkyApmExtensions().AddAspNetCoreHosting().AddHttpClient().AddSqlClient().AddGrpc() .AddEntityFrameworkCore(c => c.AddPomeloMysql().AddNpgsql().AddSqlite()); return services; } diff --git a/src/SkyApm.Agent.AspNetCore/SkyApm.Agent.AspNetCore.csproj b/src/SkyApm.Agent.AspNetCore/SkyApm.Agent.AspNetCore.csproj index 277a730bf19c4a2fd8061bccaa3ffcd4ca705c2b..d0969264bed4b2820fb01673f1e78efb65a977e7 100644 --- a/src/SkyApm.Agent.AspNetCore/SkyApm.Agent.AspNetCore.csproj +++ b/src/SkyApm.Agent.AspNetCore/SkyApm.Agent.AspNetCore.csproj @@ -22,6 +22,7 @@ + diff --git a/src/SkyApm.Agent.GeneralHost/Extensions/ServiceCollectionExtensions.cs b/src/SkyApm.Agent.GeneralHost/Extensions/ServiceCollectionExtensions.cs index 1f52b4d2ae262df81657d7f3d21fe156801e7e80..255cff1f7de8002441a1b18cce1995452b90c068 100644 --- a/src/SkyApm.Agent.GeneralHost/Extensions/ServiceCollectionExtensions.cs +++ b/src/SkyApm.Agent.GeneralHost/Extensions/ServiceCollectionExtensions.cs @@ -21,6 +21,7 @@ using Microsoft.Extensions.Hosting; using SkyApm.Config; using SkyApm.Diagnostics; using SkyApm.Diagnostics.EntityFrameworkCore; +using SkyApm.Diagnostics.Grpc; using SkyApm.Diagnostics.HttpClient; using SkyApm.Diagnostics.SqlClient; using SkyApm.Logging; @@ -60,7 +61,7 @@ namespace SkyApm.Agent.GeneralHost services.AddSingleton(); services.AddSingleton(); services.AddTracing().AddSampling().AddGrpcTransport().AddLogging(); - services.AddSkyApmExtensions().AddHttpClient().AddSqlClient() + services.AddSkyApmExtensions().AddHttpClient().AddSqlClient().AddGrpc() .AddEntityFrameworkCore(c => c.AddPomeloMysql().AddNpgsql().AddSqlite()); return services; } diff --git a/src/SkyApm.Agent.GeneralHost/SkyApm.Agent.GeneralHost.csproj b/src/SkyApm.Agent.GeneralHost/SkyApm.Agent.GeneralHost.csproj index 935cc209c2cbd85bd9df998469de0a271cbceb75..35a1c87d9faf48302eb5dd5f322dc7defeae7da5 100644 --- a/src/SkyApm.Agent.GeneralHost/SkyApm.Agent.GeneralHost.csproj +++ b/src/SkyApm.Agent.GeneralHost/SkyApm.Agent.GeneralHost.csproj @@ -21,6 +21,7 @@ + diff --git a/src/SkyApm.Diagnostics.Grpc/Client/ClientDiagnosticInterceptor.cs b/src/SkyApm.Diagnostics.Grpc/Client/ClientDiagnosticInterceptor.cs new file mode 100644 index 0000000000000000000000000000000000000000..cc8e71c47859d0c253f2cf2301b98302758bf023 --- /dev/null +++ b/src/SkyApm.Diagnostics.Grpc/Client/ClientDiagnosticInterceptor.cs @@ -0,0 +1,61 @@ +using Grpc.Core; +using Grpc.Core.Interceptors; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace SkyApm.Diagnostics.Grpc.Client +{ + public class ClientDiagnosticInterceptor : Interceptor + { + private readonly ClientDiagnosticProcessor _processor; + + public ClientDiagnosticInterceptor(ClientDiagnosticProcessor processor) + { + _processor = processor; + } + + public override TResponse BlockingUnaryCall(TRequest request, ClientInterceptorContext context, BlockingUnaryCallContinuation continuation) + { + var metadata = _processor.BeginRequest(context); + try + { + var options = context.Options.WithHeaders(metadata); + context = new ClientInterceptorContext(context.Method, context.Host, options); + var response = continuation(request, context); + _processor.EndRequest(); + return response; + } + catch (Exception ex) + { + _processor.DiagnosticUnhandledException(ex); + throw ex; + } + } + + public override AsyncUnaryCall AsyncUnaryCall(TRequest request, ClientInterceptorContext context, AsyncUnaryCallContinuation continuation) + { + var metadata = _processor.BeginRequest(context); + try + { + var options = context.Options.WithHeaders(metadata); + context = new ClientInterceptorContext(context.Method, context.Host, options); + var response = continuation(request, context); + var responseAsync = response.ResponseAsync.ContinueWith(r => + { + _processor.EndRequest(); + return r.Result; + }); + return new AsyncUnaryCall(responseAsync, response.ResponseHeadersAsync, response.GetStatus, response.GetTrailers, response.Dispose); + } + catch (Exception ex) + { + _processor.DiagnosticUnhandledException(ex); + throw ex; + } + } + + + } +} diff --git a/src/SkyApm.Diagnostics.Grpc/Client/ClientDiagnosticProcessor.cs b/src/SkyApm.Diagnostics.Grpc/Client/ClientDiagnosticProcessor.cs new file mode 100644 index 0000000000000000000000000000000000000000..d46abaf98c35f239511bf665753bc40560a5150c --- /dev/null +++ b/src/SkyApm.Diagnostics.Grpc/Client/ClientDiagnosticProcessor.cs @@ -0,0 +1,70 @@ +using Grpc.Core; +using Grpc.Core.Interceptors; +using SkyApm.Common; +using SkyApm.Tracing; +using SkyApm.Tracing.Segments; +using System; + +namespace SkyApm.Diagnostics.Grpc.Client +{ + public class ClientDiagnosticProcessor + { + private readonly ITracingContext _tracingContext; + private readonly IExitSegmentContextAccessor _segmentContextAccessor; + + public ClientDiagnosticProcessor(IExitSegmentContextAccessor segmentContextAccessor, + ITracingContext tracingContext) + { + _tracingContext = tracingContext; + _segmentContextAccessor = segmentContextAccessor; + } + + public Metadata BeginRequest(ClientInterceptorContext grpcContext) + where TRequest : class + where TResponse : class + { + var host = grpcContext.Host; + var carrierHeader = new GrpcCarrierHeaderCollection(grpcContext.Options.Headers); + var context = _tracingContext.CreateExitSegmentContext(grpcContext.Method.FullName, host, carrierHeader); + context.Span.SpanLayer = SpanLayer.RPC_FRAMEWORK; + context.Span.Component = Components.GRPC; + context.Span.Peer = new StringOrIntValue(host); + context.Span.AddTag(Tags.GRPC_METHOD_NAME, grpcContext.Method.FullName); + context.Span.AddLog( + LogEvent.Event("Grpc Client BeginRequest"), + LogEvent.Message($"Request starting {grpcContext.Method.Type} {grpcContext.Method.FullName}")); + + var metadata = new Metadata(); + foreach (var item in carrierHeader) + { + metadata.Add(item.Key, item.Value); + } + return metadata; + } + + public void EndRequest() + { + var context = _segmentContextAccessor.Context; + if (context == null) + { + return; + } + + context.Span.AddLog( + LogEvent.Event("Grpc Client EndRequest"), + LogEvent.Message($"Request finished ")); + + _tracingContext.Release(context); + } + + public void DiagnosticUnhandledException(Exception exception) + { + var context = _segmentContextAccessor.Context; + if (context != null) + { + context.Span?.ErrorOccurred(exception); + _tracingContext.Release(context); + } + } + } +} diff --git a/src/SkyApm.Diagnostics.Grpc/GrpcCarrierHeaderCollection.cs b/src/SkyApm.Diagnostics.Grpc/GrpcCarrierHeaderCollection.cs new file mode 100644 index 0000000000000000000000000000000000000000..196631b8b1a7fb2a59cb42b6cf6b2e42c18f8569 --- /dev/null +++ b/src/SkyApm.Diagnostics.Grpc/GrpcCarrierHeaderCollection.cs @@ -0,0 +1,35 @@ +using Grpc.Core; +using SkyApm.Tracing; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace SkyApm.Diagnostics.Grpc +{ + public class GrpcCarrierHeaderCollection : ICarrierHeaderCollection + { + private readonly Metadata _metadata; + + public GrpcCarrierHeaderCollection(Metadata metadata) + { + _metadata = metadata ?? new Metadata(); + } + + public void Add(string key, string value) + { + _metadata.Add(new Metadata.Entry(key, value)); + } + + public IEnumerator> GetEnumerator() + { + return _metadata.Select(m => new KeyValuePair(m.Key, m.Value)).GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return _metadata.GetEnumerator(); + } + } +} diff --git a/src/SkyApm.Diagnostics.Grpc/Server/ServerDiagnosticInterceptor.cs b/src/SkyApm.Diagnostics.Grpc/Server/ServerDiagnosticInterceptor.cs new file mode 100644 index 0000000000000000000000000000000000000000..00060a8c78792ff6c5f66cde662cd680d040c6ce --- /dev/null +++ b/src/SkyApm.Diagnostics.Grpc/Server/ServerDiagnosticInterceptor.cs @@ -0,0 +1,34 @@ +using Grpc.Core; +using Grpc.Core.Interceptors; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace SkyApm.Diagnostics.Grpc.Server +{ + public class ServerDiagnosticInterceptor : Interceptor + { + private readonly ServerDiagnosticProcessor _processor; + public ServerDiagnosticInterceptor(ServerDiagnosticProcessor processor) + { + _processor = processor; + } + + public override async Task UnaryServerHandler(TRequest request, ServerCallContext context, UnaryServerMethod continuation) + { + _processor.BeginRequest(context); + try + { + var response = await continuation(request, context); + _processor.EndRequest(context); + return response; + } + catch (Exception ex) + { + _processor.DiagnosticUnhandledException(ex); + throw ex; + } + } + } +} diff --git a/src/SkyApm.Diagnostics.Grpc/Server/ServerDiagnosticProcessor.cs b/src/SkyApm.Diagnostics.Grpc/Server/ServerDiagnosticProcessor.cs new file mode 100644 index 0000000000000000000000000000000000000000..9ba521c1d815047598f8e09d7e9ba6a441268a5c --- /dev/null +++ b/src/SkyApm.Diagnostics.Grpc/Server/ServerDiagnosticProcessor.cs @@ -0,0 +1,65 @@ +using Grpc.Core; +using SkyApm.Common; +using SkyApm.Tracing; +using SkyApm.Tracing.Segments; +using System; + +namespace SkyApm.Diagnostics.Grpc.Server +{ + public class ServerDiagnosticProcessor + { + private readonly ITracingContext _tracingContext; + private readonly IEntrySegmentContextAccessor _segmentContextAccessor; + + public ServerDiagnosticProcessor(IEntrySegmentContextAccessor segmentContextAccessor, + ITracingContext tracingContext) + { + _tracingContext = tracingContext; + _segmentContextAccessor = segmentContextAccessor; + } + + public void BeginRequest(ServerCallContext grpcContext) + { + var context = _tracingContext.CreateEntrySegmentContext(grpcContext.Method, + new GrpcCarrierHeaderCollection(grpcContext.RequestHeaders)); + context.Span.SpanLayer = SpanLayer.RPC_FRAMEWORK; + context.Span.Component = Components.GRPC; + context.Span.Peer = new StringOrIntValue(grpcContext.Peer); + context.Span.AddTag(Tags.GRPC_METHOD_NAME, grpcContext.Method); + context.Span.AddLog( + LogEvent.Event("Grpc Server BeginRequest"), + LogEvent.Message($"Request starting {grpcContext.Method}")); + } + + public void EndRequest(ServerCallContext grpcContext) + { + var context = _segmentContextAccessor.Context; + if (context == null) + { + return; + } + var statusCode = grpcContext.Status.StatusCode; + if (statusCode != StatusCode.OK) + { + context.Span.ErrorOccurred(); + } + + context.Span.AddTag(Tags.GRPC_STATUS, statusCode.ToString()); + context.Span.AddLog( + LogEvent.Event("Grpc Server EndRequest"), + LogEvent.Message($"Request finished {statusCode} ")); + + _tracingContext.Release(context); + } + + public void DiagnosticUnhandledException(Exception exception) + { + var context = _segmentContextAccessor.Context; + if (context != null) + { + context.Span?.ErrorOccurred(exception); + _tracingContext.Release(context); + } + } + } +} diff --git a/src/SkyApm.Diagnostics.Grpc/SkyApm.Diagnostics.Grpc.csproj b/src/SkyApm.Diagnostics.Grpc/SkyApm.Diagnostics.Grpc.csproj new file mode 100644 index 0000000000000000000000000000000000000000..bcafa9a6164a5f0896a06a9b48199d21c95a4851 --- /dev/null +++ b/src/SkyApm.Diagnostics.Grpc/SkyApm.Diagnostics.Grpc.csproj @@ -0,0 +1,16 @@ + + + + netstandard2.0 + + + + + + + + + + + + diff --git a/src/SkyApm.Diagnostics.Grpc/SkyWalkingBuilderExtensions.cs b/src/SkyApm.Diagnostics.Grpc/SkyWalkingBuilderExtensions.cs new file mode 100644 index 0000000000000000000000000000000000000000..10dc151eb83ff492ef24b5da54a375e8f13be145 --- /dev/null +++ b/src/SkyApm.Diagnostics.Grpc/SkyWalkingBuilderExtensions.cs @@ -0,0 +1,22 @@ +using Microsoft.Extensions.DependencyInjection; +using SkyApm.Diagnostics.Grpc.Client; +using SkyApm.Diagnostics.Grpc.Server; +using SkyApm.Utilities.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Text; + +namespace SkyApm.Diagnostics.Grpc +{ + public static class SkyWalkingBuilderExtensions + { + public static SkyApmExtensions AddGrpc(this SkyApmExtensions extensions) + { + extensions.Services.AddSingleton(); + extensions.Services.AddSingleton(); + extensions.Services.AddSingleton(); + extensions.Services.AddSingleton(); + return extensions; + } + } +} diff --git a/src/SkyApm.Transport.Grpc.Protocol/SkyApm.Transport.Grpc.Protocol.csproj b/src/SkyApm.Transport.Grpc.Protocol/SkyApm.Transport.Grpc.Protocol.csproj index 2ec1c444435aff5f92cee0ccd1557298f77afde7..8f41da2b2aca33a8118402a3d198fe323e061521 100644 --- a/src/SkyApm.Transport.Grpc.Protocol/SkyApm.Transport.Grpc.Protocol.csproj +++ b/src/SkyApm.Transport.Grpc.Protocol/SkyApm.Transport.Grpc.Protocol.csproj @@ -16,7 +16,7 @@ - +