File: LanguageClient\VisualStudioLogHubLoggerFactory.cs
Web Access
Project: src\src\VisualStudio\Core\Def\Microsoft.VisualStudio.LanguageServices_pxr0p0dn_wpftmp.csproj (Microsoft.VisualStudio.LanguageServices)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.LanguageServer;
using Microsoft.CommonLanguageServerProtocol.Framework;
using Microsoft.ServiceHub.Framework;
using Microsoft.VisualStudio.LogHub;
using Microsoft.VisualStudio.RpcContracts.Logging;
using Microsoft.VisualStudio.Shell.ServiceBroker;
using StreamJsonRpc;
 
namespace Microsoft.VisualStudio.LanguageServices.Implementation.LanguageClient;
 
[Export(typeof(ILspServiceLoggerFactory))]
internal class VisualStudioLogHubLoggerFactory : ILspServiceLoggerFactory
{
    /// <summary>
    /// A unique, always increasing, ID we use to identify this server in our loghub logs.  Needed so that if our
    /// server is restarted that we can have a new logstream for the new server.
    /// </summary>
    private static int s_logHubSessionId;
 
    private readonly IVsService<IBrokeredServiceContainer> _brokeredServiceContainer;
 
    [ImportingConstructor]
    [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
    public VisualStudioLogHubLoggerFactory(
        IVsService<SVsBrokeredServiceContainer, IBrokeredServiceContainer> brokeredServiceContainer)
    {
        _brokeredServiceContainer = brokeredServiceContainer;
    }
 
    public async Task<AbstractLspLogger> CreateLoggerAsync(string serverTypeName, JsonRpc jsonRpc, CancellationToken cancellationToken)
    {
        var logName = $"Roslyn.{serverTypeName}.{Interlocked.Increment(ref s_logHubSessionId)}";
        var logId = new LogId(logName, new ServiceMoniker(typeof(AbstractLanguageServer<>).FullName));
 
        var serviceContainer = await _brokeredServiceContainer.GetValueAsync(cancellationToken).ConfigureAwait(false);
        var service = serviceContainer.GetFullAccessServiceBroker();
 
        var configuration = await TraceConfiguration.CreateTraceConfigurationInstanceAsync(service, ownsServiceBroker: true, cancellationToken).ConfigureAwait(false);
 
        // Register the default log level as information.
        // Loghub will take care of cleaning up older logs from past sessions / current session
        // if it decides the log file sizes are too large.
        var loggingLevel = SourceLevels.ActivityTracing | SourceLevels.Information;
 
        var logOptions = new RpcContracts.Logging.LoggerOptions(new LoggingLevelSettings(loggingLevel));
        var traceSource = await configuration.RegisterLogSourceAsync(logId, logOptions, cancellationToken).ConfigureAwait(false);
 
        // Associate this trace source with the jsonrpc conduit.  This ensures that we can associate logs we report
        // with our callers and the operations they are performing.
        jsonRpc.ActivityTracingStrategy = new CorrelationManagerTracingStrategy { TraceSource = traceSource };
 
        return new LogHubLspLogger(configuration, traceSource);
    }
}