Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add logging #48235

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 56 additions & 11 deletions src/Workspaces/CoreTestUtilities/Remote/InProcRemostHostClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,20 @@
using System.Diagnostics;
using System.IO;
using System.IO.Pipelines;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using System.Runtime.Remoting;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Experiments;
using Microsoft.CodeAnalysis.Extensions;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Serialization;
using Microsoft.CodeAnalysis.TodoComments;
using Microsoft.ServiceHub.Framework;
using Microsoft.VisualStudio.Threading;
using Nerdbank.Streams;
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
using StreamJsonRpc;
using Xunit.Abstractions;

namespace Microsoft.CodeAnalysis.Remote.Testing
{
Expand All @@ -41,7 +39,7 @@ public static async Task<RemoteHostClient> CreateAsync(HostWorkspaceServices ser

var remoteHostStream = await inprocServices.RequestServiceAsync(WellKnownServiceHubService.RemoteHost).ConfigureAwait(false);

var instance = new InProcRemoteHostClient(services, inprocServices, remoteHostStream);
var instance = new InProcRemoteHostClient(services, inprocServices, traceListener, remoteHostStream);

// make sure connection is done right
var uiCultureLCIDE = 0;
Expand All @@ -61,10 +59,19 @@ await instance._endPoint.InvokeAsync(
private InProcRemoteHostClient(
HostWorkspaceServices services,
InProcRemoteServices inprocServices,
TraceListener? traceListener,
Stream stream)
{
_workspaceServices = services;
_logger = new TraceSource("Default");
_logger = new TraceSource("Default")
{
Switch = { Level = SourceLevels.Information },
};

if (traceListener != null)
{
_logger.Listeners.Add(traceListener);
}

_inprocServices = inprocServices;

Expand Down Expand Up @@ -147,7 +154,10 @@ public override void Dispose()
}

private void OnDisconnected(JsonRpcDisconnectedEventArgs e)
=> Dispose();
{
_logger?.TraceInformation($"Closing InProcRemoteHostClient ({e.Reason}) Exception: {e.Exception})");
Dispose();
}

public sealed class ServiceProvider : IServiceProvider
{
Expand Down Expand Up @@ -193,7 +203,21 @@ public event EventHandler<BrokeredServicesChangedEventArgs>? AvailabilityChanged

public ValueTask<T?> GetProxyAsync<T>(ServiceRpcDescriptor descriptor, ServiceActivationOptions options, CancellationToken cancellationToken) where T : class
{
var pipePair = FullDuplexStream.CreatePipePair();
var fullDuplexStreams = FullDuplexStream.CreatePair();

if (descriptor.Moniker == SolutionAssetProvider.ServiceDescriptor.Moniker)
{
//MonitorForDisposal(ref fullDuplexStreams.Item1, descriptor, 1, _services.ServiceProvider.TraceSource);
//MonitorForDisposal(ref fullDuplexStreams.Item2, descriptor, 2, _services.ServiceProvider.TraceSource);
}

var pipePair = (fullDuplexStreams.Item1.UsePipe(), fullDuplexStreams.Item2.UsePipe());

if (((ServiceJsonRpcDescriptor)descriptor).MultiplexingStreamOptions is { } multiplexingStreamOptions && _services.ServiceProvider.TraceSource is { } traceSource)
{
descriptor = (ServiceDescriptor)((ServiceDescriptor)descriptor).WithMultiplexingStream(
new MultiplexingStream.Options(multiplexingStreamOptions) { TraceSource = traceSource });
}

var clientConnection = descriptor
.WithTraceSource(_services.ServiceProvider.TraceSource)
Expand All @@ -214,11 +238,26 @@ public event EventHandler<BrokeredServicesChangedEventArgs>? AvailabilityChanged

// Creates service instance and connects it to the pipe.
// We don't need to store the instance anywhere.
_ = _services.CreateBrokeredService(descriptor, pipePair.Item1, options);
_ = _services.CreateBrokeredService((ServiceDescriptor)descriptor, pipePair.Item1, options);

clientConnection.StartListening();

return new ValueTask<T?>(clientConnection.ConstructRpcClient<T>());

//static void MonitorForDisposal(ref Stream stream, ServiceRpcDescriptor descriptor, int item, TraceSource traceSource)
//{
// if (traceSource is null)
// return;

// var wrappedStream = new MonitoringStream(stream);
// wrappedStream.Disposed +=
// delegate
// {
// traceSource?.TraceInformation($"Disposing pipe {item} for '{descriptor.Moniker}': {new StackTrace()}");
// //Debugger.Launch();
// };
// stream = wrappedStream;
//}
}
}

Expand All @@ -236,7 +275,7 @@ public InProcRemoteServices(HostWorkspaceServices workspaceServices, TraceListen
{
var remoteLogger = new TraceSource("InProcRemoteClient")
{
Switch = { Level = SourceLevels.Verbose },
Switch = { Level = SourceLevels.Information },
};

if (traceListener != null)
Expand Down Expand Up @@ -298,14 +337,20 @@ public void RegisterRemoteBrokeredService(BrokeredServiceBase.IFactory serviceFa
_remoteBrokeredServicesMap.Add(moniker, serviceFactory);
}

public object CreateBrokeredService(ServiceRpcDescriptor descriptor, IDuplexPipe pipe, ServiceActivationOptions options)
public object CreateBrokeredService(ServiceJsonRpcDescriptor descriptor, IDuplexPipe pipe, ServiceActivationOptions options)
{
if (_inProcBrokeredServicesMap.TryGetValue(descriptor.Moniker, out var inProcFactory))
{
// This code is similar to service creation implemented in BrokeredServiceBase.FactoryBase.
// Currently don't support callback creation as we don't have in-proc service with callbacks yet.
Contract.ThrowIfFalse(descriptor.ClientInterface == null);

if (descriptor.MultiplexingStreamOptions is not null && ServiceProvider.TraceSource is { } traceSource)
{
descriptor = ((ServiceDescriptor)descriptor).WithMultiplexingStream(
new MultiplexingStream.Options(descriptor.MultiplexingStreamOptions) { TraceSource = traceSource });
}

var serviceConnection = descriptor.WithTraceSource(ServiceProvider.TraceSource).ConstructRpcConnection(pipe);
var service = inProcFactory();

Expand Down
24 changes: 24 additions & 0 deletions src/Workspaces/Remote/Core/ServiceDescriptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#nullable enable

using System;
using System.Diagnostics;
using System.IO.Pipelines;
using System.Reflection;
using MessagePack;
Expand Down Expand Up @@ -73,6 +74,16 @@ private static MessagePackFormatter ConfigureFormatter(MessagePackFormatter form

protected override JsonRpcConnection CreateConnection(JsonRpc jsonRpc)
{
//if (Moniker == SolutionAssetProvider.ServiceDescriptor.Moniker)
//{
// jsonRpc.Disconnected +=
// delegate
// {
// jsonRpc.TraceSource?.TraceInformation($"Disconnected '{Moniker}': {new StackTrace()}");
// //Debugger.Launch();
// };
//}

jsonRpc.CancelLocallyInvokedMethodsWhenConnectionIsClosed = true;
var connection = base.CreateConnection(jsonRpc);
connection.LocalRpcTargetOptions = s_jsonRpcTargetOptions;
Expand All @@ -99,6 +110,19 @@ public override ServiceRpcDescriptor WithMultiplexingStream(MultiplexingStream?
return result;
}

public new ServiceDescriptor WithMultiplexingStream(MultiplexingStream.Options multiplexingStreamOptions)
{
var baseResult = base.WithMultiplexingStream(multiplexingStreamOptions);
if (baseResult is ServiceDescriptor serviceDescriptor)
return serviceDescriptor;

// Work around incorrect implementation in 16.8 Preview 2
var result = (ServiceDescriptor)WithMultiplexingStream((MultiplexingStream?)null);
result = (ServiceDescriptor)result.Clone();
typeof(ServiceJsonRpcDescriptor).GetProperty(nameof(MultiplexingStreamOptions))!.SetValue(result, value: multiplexingStreamOptions?.GetFrozenCopy());
return result;
}

internal static class TestAccessor
{
public static MessagePackSerializerOptions Options => s_options;
Expand Down
2 changes: 1 addition & 1 deletion src/Workspaces/Remote/Core/ServiceDescriptors.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ internal static string GetQualifiedServiceName(Type serviceInterface)
return new(serviceInterface, (descriptor32, descriptor64));
}

public static ServiceRpcDescriptor GetServiceDescriptor(Type serviceType, bool isRemoteHost64Bit)
public static ServiceJsonRpcDescriptor GetServiceDescriptor(Type serviceType, bool isRemoteHost64Bit)
{
var (descriptor32, descriptor64) = Descriptors[serviceType];
return isRemoteHost64Bit ? descriptor64 : descriptor32;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,13 @@ internal TService Create(
{
var descriptor = ServiceDescriptors.GetServiceDescriptor(typeof(TService), isRemoteHost64Bit: IntPtr.Size == 8);
var serviceHubTraceSource = (TraceSource)hostProvidedServices.GetService(typeof(TraceSource));

if (descriptor.MultiplexingStreamOptions is not null && serviceHubTraceSource is not null)
{
descriptor = ((ServiceDescriptor)descriptor).WithMultiplexingStream(
new MultiplexingStream.Options(descriptor.MultiplexingStreamOptions) { TraceSource = serviceHubTraceSource });
}

var serverConnection = descriptor.WithTraceSource(serviceHubTraceSource).ConstructRpcConnection(pipe);

var args = new ServiceConstructionArguments(hostProvidedServices, serviceBroker);
Expand Down