Include gRPC messages in plugin log

This commit is contained in:
Liza 2022-11-24 23:28:31 +01:00
parent ce1285bff9
commit 350da5e916
5 changed files with 105 additions and 8 deletions

View File

@ -0,0 +1,77 @@
using Dalamud.Logging;
using Microsoft.Extensions.Logging;
using System;
using System.Runtime.CompilerServices;
namespace Pal.Client.Net
{
internal class GrpcLogger : ILogger
{
private readonly string _name;
public GrpcLogger(string name)
{
_name = name;
}
public IDisposable BeginScope<TState>(TState state) => NullScope.Instance;
public bool IsEnabled(LogLevel logLevel) => logLevel != LogLevel.None;
[MethodImpl(MethodImplOptions.NoInlining)] // PluginLog detects the plugin name as `Microsoft.Extensions.Logging` if inlined
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
{
if (!IsEnabled(logLevel))
return;
if (formatter == null)
throw new ArgumentNullException(nameof(formatter));
string message = $"gRPC[{_name}] {formatter(state, null)}";
if (string.IsNullOrEmpty(message))
return;
#pragma warning disable CS8604 // the nullability on PluginLog methods is wrong and allows nulls for exceptions, WriteLog even declares the parameter as `Exception? exception = null`
switch (logLevel)
{
case LogLevel.Critical:
PluginLog.Fatal(exception, message);
break;
case LogLevel.Error:
PluginLog.Error(exception, message);
break;
case LogLevel.Warning:
PluginLog.Warning(exception, message);
break;
case LogLevel.Information:
PluginLog.Information(exception, message);
break;
case LogLevel.Debug:
PluginLog.Debug(exception, message);
break;
case LogLevel.Trace:
PluginLog.Verbose(exception, message);
break;
}
#pragma warning restore CS8604
}
private class NullScope : IDisposable
{
public static NullScope Instance { get; } = new NullScope();
private NullScope()
{
}
public void Dispose()
{
}
}
}
}

View File

@ -0,0 +1,14 @@
using Microsoft.Extensions.Logging;
using System;
namespace Pal.Client.Net
{
internal class GrpcLoggerProvider : ILoggerProvider
{
public ILogger CreateLogger(string categoryName) => new GrpcLogger(categoryName);
public void Dispose()
{
}
}
}

View File

@ -2,6 +2,7 @@
using Dalamud.Logging;
using Grpc.Core;
using Grpc.Net.Client;
using Microsoft.Extensions.Logging;
using Palace;
using System;
using System.Collections.Generic;
@ -13,7 +14,7 @@ using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
namespace Pal.Client
namespace Pal.Client.Net
{
internal class RemoteApi : IDisposable
{
@ -24,6 +25,8 @@ namespace Pal.Client
#endif
private readonly string UserAgent = $"{typeof(RemoteApi).Assembly.GetName().Name?.Replace(" ", "")}/{typeof(RemoteApi).Assembly.GetName().Version?.ToString(2)}";
private readonly ILoggerFactory _grpcToPluginLogLoggerFactory = LoggerFactory.Create(builder => builder.AddProvider(new GrpcLoggerProvider()).AddFilter("Grpc", LogLevel.Trace));
private GrpcChannel? _channel;
private LoginReply? _lastLoginReply;
private bool _warnedAboutUpgrade = false;
@ -43,7 +46,7 @@ namespace Pal.Client
private string PartialAccountId =>
AccountId?.ToString()?.PadRight(14).Substring(0, 13) ?? "[no account id]";
private async Task<(bool Success, string Error)> TryConnect(CancellationToken cancellationToken, bool retry = true)
private async Task<(bool Success, string Error)> TryConnect(CancellationToken cancellationToken, ILoggerFactory? loggerFactory = null, bool retry = true)
{
if (Service.Configuration.Mode != Configuration.EMode.Online)
{
@ -62,7 +65,8 @@ namespace Pal.Client
{
ConnectTimeout = TimeSpan.FromSeconds(5),
SslOptions = GetSslClientAuthenticationOptions(),
}
},
LoggerFactory = loggerFactory,
});
PluginLog.Information($"TryConnect: Connecting to upstream service at {remoteUrl}");
@ -105,11 +109,11 @@ namespace Pal.Client
_lastLoginReply = await accountClient.LoginAsync(new LoginRequest { AccountId = AccountId?.ToString() }, headers: UnauthorizedHeaders(), deadline: DateTime.UtcNow.AddSeconds(10), cancellationToken: cancellationToken);
if (_lastLoginReply.Success)
{
PluginLog.Information($"TryConnect: Login successful with account id: {PartialAccountId}, auth token: {_lastLoginReply.AuthToken}");
PluginLog.Information($"TryConnect: Login successful with account id: {PartialAccountId}");
}
else
{
PluginLog.Error($"TryConnect: Login failed with error { _lastLoginReply.Error}");
PluginLog.Error($"TryConnect: Login failed with error {_lastLoginReply.Error}");
if (_lastLoginReply.Error == LoginError.InvalidAccountId)
{
AccountId = null;
@ -154,7 +158,7 @@ namespace Pal.Client
{
_warnedAboutUpgrade = false;
var connectionResult = await TryConnect(cancellationToken);
var connectionResult = await TryConnect(cancellationToken, loggerFactory: _grpcToPluginLogLoggerFactory);
if (!connectionResult.Success)
return $"Could not connect to server: {connectionResult.Error}";
@ -217,7 +221,7 @@ namespace Pal.Client
private Marker CreateMarkerFromNetworkObject(PalaceObject obj) =>
new Marker((Marker.EType)obj.Type, new Vector3(obj.X, obj.Y, obj.Z), Guid.Parse(obj.NetworkId));
public async Task<(bool, List<FloorStatistics>)> FetchStatistics(CancellationToken cancellationToken = default)
{
if (!await Connect(cancellationToken))

View File

@ -3,7 +3,7 @@
<PropertyGroup>
<TargetFramework>net6.0-windows</TargetFramework>
<LangVersion>9.0</LangVersion>
<Version>1.17.0.0</Version>
<Version>1.18.0.0</Version>
<Nullable>enable</Nullable>
</PropertyGroup>
@ -37,6 +37,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
</ItemGroup>
<ItemGroup>

View File

@ -8,6 +8,7 @@ using Dalamud.Game.Gui;
using Dalamud.Interface.Windowing;
using Dalamud.IoC;
using Dalamud.Plugin;
using Pal.Client.Net;
namespace Pal.Client
{