diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj index 135ce26cbd23500f8dc500670a594edd3c9d85ed..183c44235832e8b72c362aad2d7f78fb0319133e 100644 --- a/src/csharp/Grpc.Core/Grpc.Core.csproj +++ b/src/csharp/Grpc.Core/Grpc.Core.csproj @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="utf-8"?> +<?xml version="1.0" encoding="utf-8"?> <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> @@ -33,6 +33,7 @@ <Reference Include="System" /> </ItemGroup> <ItemGroup> + <Compile Include="Internal\GrpcLog.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="RpcException.cs" /> <Compile Include="Calls.cs" /> @@ -65,9 +66,17 @@ <Compile Include="Utils\BenchmarkUtil.cs" /> <Compile Include="Utils\ExceptionHelper.cs" /> </ItemGroup> + <Choose> + <!-- Under Windows, automatically copy the C core library to output dir. + Under Monodevelop it's not supported so it has no effect. --> + <When Condition=" '$(Platform)' == 'AnyCPU' "> + <ItemGroup> + <Content Include="..\..\..\vsprojects\vs2013\Debug\grpc_csharp_ext.dll"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </Content> + </ItemGroup> + </When> + <Otherwise/> + </Choose> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> - <ItemGroup> - <Folder Include="Internal\" /> - <Folder Include="Utils\" /> - </ItemGroup> </Project> \ No newline at end of file diff --git a/src/csharp/Grpc.Core/GrpcEnvironment.cs b/src/csharp/Grpc.Core/GrpcEnvironment.cs index 0e3a0a581cd8a71717bcfa318f429d64e4c65a0c..d3a8da4729e3ff3f69c29d03b9d068828d4cf466 100644 --- a/src/csharp/Grpc.Core/GrpcEnvironment.cs +++ b/src/csharp/Grpc.Core/GrpcEnvironment.cs @@ -107,6 +107,7 @@ namespace Grpc.Core /// </summary> private GrpcEnvironment() { + GrpcLog.RedirectNativeLogs(Console.Error); grpcsharp_init(); threadPool = new GrpcThreadPool(THREAD_POOL_SIZE); threadPool.Start(); diff --git a/src/csharp/Grpc.Core/Internal/GrpcLog.cs b/src/csharp/Grpc.Core/Internal/GrpcLog.cs new file mode 100644 index 0000000000000000000000000000000000000000..98768d05c6db83f9fda9f23d61624adc35bfaa00 --- /dev/null +++ b/src/csharp/Grpc.Core/Internal/GrpcLog.cs @@ -0,0 +1,94 @@ +#region Copyright notice and license + +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#endregion + +using System; +using System.Collections.Concurrent; +using System.Diagnostics; +using System.IO; +using System.Runtime.InteropServices; +using System.Threading; + +namespace Grpc.Core.Internal +{ + internal delegate void GprLogDelegate(IntPtr fileStringPtr, Int32 line, UInt64 threadId, IntPtr severityStringPtr, IntPtr msgPtr); + + /// <summary> + /// Logs from gRPC C core library can get lost if your application is not a console app. + /// This class allows redirection of logs to arbitrary destination. + /// </summary> + internal static class GrpcLog + { + static object staticLock = new object(); + static GprLogDelegate writeCallback; + static TextWriter dest; + + [DllImport("grpc_csharp_ext.dll")] + static extern void grpcsharp_redirect_log(GprLogDelegate callback); + + /// <summary> + /// Sets text writer as destination for logs from native gRPC C core library. + /// Only first invocation has effect. + /// </summary> + /// <param name="textWriter"></param> + public static void RedirectNativeLogs(TextWriter textWriter) + { + lock (staticLock) + { + if (writeCallback == null) + { + writeCallback = new GprLogDelegate(HandleWrite); + dest = textWriter; + grpcsharp_redirect_log(writeCallback); + } + } + } + + private static void HandleWrite(IntPtr fileStringPtr, Int32 line, UInt64 threadId, IntPtr severityStringPtr, IntPtr msgPtr) + { + try + { + // TODO: DateTime format used here is different than in C core. + dest.WriteLine(string.Format("{0}{1} {2} {3}:{4}: {5}", + Marshal.PtrToStringAnsi(severityStringPtr), DateTime.Now, + threadId, + Marshal.PtrToStringAnsi(fileStringPtr), + line, + Marshal.PtrToStringAnsi(msgPtr))); + } + catch (Exception e) + { + Console.WriteLine("Caught exception in native callback " + e); + } + } + } +} diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c index 18e0431e3b22acdf2604d0e3c21f0ce45ecfdcfd..8f5a414187273b34250d1a8ad423e2efda6bee3d 100644 --- a/src/csharp/ext/grpc_csharp_ext.c +++ b/src/csharp/ext/grpc_csharp_ext.c @@ -35,9 +35,10 @@ #include <grpc/support/port_platform.h> #include <grpc/support/alloc.h> -#include <grpc/grpc.h> #include <grpc/support/log.h> #include <grpc/support/slice.h> +#include <grpc/support/thd.h> +#include <grpc/grpc.h> #include <string.h> @@ -345,14 +346,19 @@ grpcsharp_call_start_unary(grpc_call *call, callback_funcptr callback, /* Synchronous unary call */ GPR_EXPORT void GPR_CALLTYPE -grpcsharp_call_blocking_unary(grpc_call *call, grpc_completion_queue *dedicated_cq, callback_funcptr callback, - const char *send_buffer, size_t send_buffer_len) { - GPR_ASSERT(grpcsharp_call_start_unary(call, callback, send_buffer, send_buffer_len) == GRPC_CALL_OK); +grpcsharp_call_blocking_unary(grpc_call *call, + grpc_completion_queue *dedicated_cq, + callback_funcptr callback, + const char *send_buffer, size_t send_buffer_len) { + GPR_ASSERT(grpcsharp_call_start_unary(call, callback, send_buffer, + send_buffer_len) == GRPC_CALL_OK); /* TODO: we would like to use pluck, but we don't know the tag */ - GPR_ASSERT(grpcsharp_completion_queue_next_with_callback(dedicated_cq) == GRPC_OP_COMPLETE); + GPR_ASSERT(grpcsharp_completion_queue_next_with_callback(dedicated_cq) == + GRPC_OP_COMPLETE); grpc_completion_queue_shutdown(dedicated_cq); - GPR_ASSERT(grpcsharp_completion_queue_next_with_callback(dedicated_cq) == GRPC_QUEUE_SHUTDOWN); + GPR_ASSERT(grpcsharp_completion_queue_next_with_callback(dedicated_cq) == + GRPC_QUEUE_SHUTDOWN); } GPR_EXPORT grpc_call_error GPR_CALLTYPE @@ -579,6 +585,25 @@ grpcsharp_server_request_call(grpc_server *server, grpc_completion_queue *cq, &(ctx->server_rpc_new.request_metadata), cq, ctx); } +/* Logging */ + +typedef void(GPR_CALLTYPE *grpcsharp_log_func)(const char *file, gpr_int32 line, + gpr_uint64 thd_id, + const char *severity_string, + const char *msg); +static grpcsharp_log_func log_func = NULL; + +/* Redirects gpr_log to log_func callback */ +static void grpcsharp_log_handler(gpr_log_func_args *args) { + log_func(args->file, args->line, gpr_thd_currentid(), + gpr_log_severity_string(args->severity), args->message); +} + +GPR_EXPORT void GPR_CALLTYPE grpcsharp_redirect_log(grpcsharp_log_func func) { + GPR_ASSERT(func); + log_func = func; + gpr_set_log_function(grpcsharp_log_handler); +} /* For testing */ GPR_EXPORT void GPR_CALLTYPE @@ -587,7 +612,4 @@ grpcsharp_test_callback(callback_funcptr callback) { } /* For testing */ -GPR_EXPORT void *GPR_CALLTYPE -grpcsharp_test_nop(void *ptr) { - return ptr; -} +GPR_EXPORT void *GPR_CALLTYPE grpcsharp_test_nop(void *ptr) { return ptr; }