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

Support caller informations #145

Merged
merged 5 commits into from
Jan 26, 2024
Merged
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
22 changes: 14 additions & 8 deletions sandbox/GeneratorSandbox/GeneratedMock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,31 +26,37 @@ public static void CouldNotOpenSocket2(this ILogger<FooBarBaz> logger, string ho
logger.Log(LogLevel.Information, -1, new CouldNotOpenSocketState(hostName, ipAddress), exception, (state, ex) => state.ToString());
}


public static void CouldNotOpenSocketWithCaller(this ILogger<FooBarBaz> logger, string hostName, int ipAddress, [CallerLineNumber] int lineNumber = 0)
{
if (!logger.IsEnabled(LogLevel.Information)) return;
logger.Log(LogLevel.Information, -1, new CouldNotOpenSocketState(hostName, ipAddress, lineNumber), null, (state, ex) => state.ToString());
}

[ZLoggerMessage(LogLevel.Information, "Could not open socket to {hostName} {ipAddress}.")]
public static partial void CouldNotOpenSocket3(this ILogger<FooBarBaz> logger, string hostName, int ipAddress);




}

file readonly struct CouldNotOpenSocketState : IZLoggerFormattable, IReadOnlyList<KeyValuePair<string, object?>>
file readonly struct CouldNotOpenSocketState : IZLoggerFormattable, ICallerTracable, IReadOnlyList<KeyValuePair<string, object?>>
{
static readonly JsonEncodedText _jsonParameter_hostName = JsonEncodedText.Encode("hostName");
static readonly JsonEncodedText _jsonParameter_ipAddress = JsonEncodedText.Encode("ipAddress");

public string? CallerMemberName { get; }
public string? CallerFilePath { get; }
public int CallerLineNumber { get; }

readonly string hostName;
readonly int ipAddress;

public CouldNotOpenSocketState(string hostName, int ipAddress)
public CouldNotOpenSocketState(string hostName, int ipAddress, int callerLineNumber = 0)
{
this.hostName = hostName;
this.ipAddress = ipAddress;
CallerLineNumber = callerLineNumber;
}

public IZLoggerEntry CreateEntry(LogInfo info)
public IZLoggerEntry CreateEntry(in LogInfo info)
{
return ZLoggerEntry<CouldNotOpenSocketState>.Create(info, this);
}
Expand Down Expand Up @@ -197,7 +203,7 @@ public SamplerState2(global::System.Guid? banana, global::System.DateTime? dt)
this.dt = dt;
}

public IZLoggerEntry CreateEntry(LogInfo info)
public IZLoggerEntry CreateEntry(in LogInfo info)
{
return ZLoggerEntry<SamplerState2>.Create(info, this);
}
Expand Down
38 changes: 34 additions & 4 deletions src/ZLogger.Generator/ZLoggerGenerator.Emitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ public void Emit()
public void EmitStructState(LogMethodDeclaration method)
{
var methodParameters = method.MethodParameters.Where(x => x.IsParameter).ToArray();
var callerInfoParameters = method.MethodParameters.Where(x => x.IsCallerInfo).ToArray();

var stateTypeName = $"{method.TargetMethod.Name}State";
var parameterCount = methodParameters.Length;

var jsonParameters = methodParameters
.Select(x => $" static readonly global::System.Text.Json.JsonEncodedText _jsonParameter_{x.LinkedMessageSegment.NameParameter} = global::System.Text.Json.JsonEncodedText.Encode(\"{x.LinkedMessageSegment.GetPropertyName()}\");")
Expand All @@ -63,6 +63,7 @@ public void EmitStructState(LogMethodDeclaration method)
.StringJoinNewLine();

var constructorParameters = methodParameters
.Concat(callerInfoParameters)
.Select(x => $"{x.Symbol.Type.ToFullyQualifiedFormatString()} {x.Symbol.Name}")
.StringJoinComma();

Expand All @@ -71,18 +72,45 @@ public void EmitStructState(LogMethodDeclaration method)
.StringJoinNewLine();

sb.AppendLine($$"""
readonly struct {{stateTypeName}} : IZLoggerFormattable, IReadOnlyList<KeyValuePair<string, object?>>
readonly struct {{stateTypeName}} : IZLoggerFormattable, ICallerTracable, IReadOnlyList<KeyValuePair<string, object?>>
{
public string? CallerMemberName { get; }
public string? CallerFilePath { get; }
public int CallerLineNumber { get; }

{{jsonParameters}}

{{fieldParameters}}

public {{stateTypeName}}({{constructorParameters}})
{
{{constructorBody}}
""");
if (callerInfoParameters.Length > 0)
{
if (callerInfoParameters.FirstOrDefault(x => x.IsCallerMemberName) is { } callerMemberNameArg)
{
sb.AppendLine($$"""
CallerMemberName = {{callerMemberNameArg.Symbol.Name}};
""");
}
if (callerInfoParameters.FirstOrDefault(x => x.IsCallerFilePath) is { } callerFilePathArg)
{
sb.AppendLine($$"""
CallerFilePath = {{callerFilePathArg.Symbol.Name}};
""");
}
if (callerInfoParameters.FirstOrDefault(x => x.IsCallerLineNumber) is { } callerLineNumberArg)
{
sb.AppendLine($$"""
CallerLineNumber = {{callerLineNumberArg.Symbol.Name}};
""");
}
}
sb.AppendLine($$"""
}

public IZLoggerEntry CreateEntry(LogInfo info)
public IZLoggerEntry CreateEntry(in LogInfo info)
{
return ZLoggerEntry<{{stateTypeName}}>.Create(info, this);
}
Expand Down Expand Up @@ -269,6 +297,7 @@ public void Dispose() { }
void EmitLogBody(LogMethodDeclaration method)
{
var methodParameters = method.MethodParameters.Where(x => x.IsParameter).ToArray();
var callerInfoParameters = method.MethodParameters.Where(x => x.IsCallerInfo).ToArray();
var modifiers = method.TargetSyntax.Modifiers.ToString();
var extension = method.TargetMethod.IsExtensionMethod ? "this " : string.Empty;

Expand All @@ -294,6 +323,7 @@ void EmitLogBody(LogMethodDeclaration method)
.StringJoinComma();

var newParameters = methodParameters
.Concat(callerInfoParameters)
.Select(x => $"{x.Symbol.Name}")
.StringJoinComma();

Expand Down
53 changes: 41 additions & 12 deletions src/ZLogger.Generator/ZLoggerGenerator.Parser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,25 @@ internal record LogMethodDeclaration(

public partial class MethodParameter
{
public required IParameterSymbol Symbol { get; init; }
public IParameterSymbol Symbol { get; }
public bool IsFirstLogger { get; init; }
public bool IsFirstLogLevel { get; init; }
public bool IsFirstException { get; init; }
public bool IsCallerMemberName { get; init; }
public bool IsCallerFilePath { get; init; }
public bool IsCallerLineNumber { get; init; }

public bool IsParameter => !IsFirstLogger && !IsFirstLogLevel && !IsFirstException;
public bool IsParameter => !IsFirstLogger && !IsFirstLogLevel && !IsFirstException && !IsCallerInfo;
public bool IsCallerInfo => IsCallerMemberName || IsCallerFilePath || IsCallerLineNumber;

// set from outside, if many segments was linked, use first-one.
public MessageSegment LinkedMessageSegment { get; set; } = default!;

public MethodParameter(IParameterSymbol symbol)
{
Symbol = symbol;
}

public bool IsEnumerable()
{
if (!IsParameter) return false;
Expand All @@ -46,9 +55,12 @@ internal class Parser
SourceProductionContext context;
ImmutableArray<GeneratorAttributeSyntaxContext> sources;

INamedTypeSymbol loggerSymbol;
INamedTypeSymbol logLevelSymbol;
INamedTypeSymbol exceptionSymbol;
readonly INamedTypeSymbol loggerSymbol;
readonly INamedTypeSymbol logLevelSymbol;
readonly INamedTypeSymbol exceptionSymbol;
readonly INamedTypeSymbol callerMemberNameAttributeSymbol;
readonly INamedTypeSymbol callerFilePathAttributeSymbol;
readonly INamedTypeSymbol callerLineNumberAttributeSymbol;

public Parser(SourceProductionContext context, ImmutableArray<GeneratorAttributeSyntaxContext> sources)
{
Expand All @@ -59,6 +71,9 @@ public Parser(SourceProductionContext context, ImmutableArray<GeneratorAttribute
this.loggerSymbol = GetTypeByMetadataName(compilation, "Microsoft.Extensions.Logging.ILogger");
this.logLevelSymbol = GetTypeByMetadataName(compilation, "Microsoft.Extensions.Logging.LogLevel");
this.exceptionSymbol = GetTypeByMetadataName(compilation, "System.Exception");
this.callerMemberNameAttributeSymbol = GetTypeByMetadataName(compilation, "System.Runtime.CompilerServices.CallerMemberNameAttribute");
this.callerFilePathAttributeSymbol = GetTypeByMetadataName(compilation, "System.Runtime.CompilerServices.CallerFilePathAttribute");
this.callerLineNumberAttributeSymbol = GetTypeByMetadataName(compilation, "System.Runtime.CompilerServices.CallerLineNumberAttribute");
}

static INamedTypeSymbol GetTypeByMetadataName(Compilation compilation, string metadataName)
Expand Down Expand Up @@ -288,9 +303,8 @@ public ParseResult[] Parse()
if (isLogger)
{
foundFirstLogger = true;
result[i] = new MethodParameter
result[i] = new MethodParameter(p)
{
Symbol = p,
IsFirstLogger = true,
};
continue;
Expand All @@ -302,9 +316,8 @@ public ParseResult[] Parse()
if (isLogLevel)
{
foundFirstLogLevel = true;
result[i] = new MethodParameter
result[i] = new MethodParameter(p)
{
Symbol = p,
IsFirstLogLevel = true,
};
continue;
Expand All @@ -316,16 +329,32 @@ public ParseResult[] Parse()
if (isException)
{
foundFirstException = true;
result[i] = new MethodParameter
result[i] = new MethodParameter(p)
{
Symbol = p,
IsFirstException = true,
};
continue;
}
}

result[i] = new MethodParameter { Symbol = p };
var attributes = p.GetAttributes();
if (attributes.Any(x => SymbolEqualityComparer.Default.Equals(x.AttributeClass, callerMemberNameAttributeSymbol)))
{
result[i] = new MethodParameter(p) { IsCallerMemberName = true };
continue;
}
if (attributes.Any(x => SymbolEqualityComparer.Default.Equals(x.AttributeClass, callerFilePathAttributeSymbol)))
{
result[i] = new MethodParameter(p) { IsCallerFilePath = true };
continue;
}
if (attributes.Any(x => SymbolEqualityComparer.Default.Equals(x.AttributeClass, callerLineNumberAttributeSymbol)))
{
result[i] = new MethodParameter(p) { IsCallerLineNumber = true };
continue;
}

result[i] = new MethodParameter(p);
}

return (result, foundFirstLogLevel);
Expand Down
67 changes: 36 additions & 31 deletions src/ZLogger/IZLoggerFormattable.cs
Original file line number Diff line number Diff line change
@@ -1,36 +1,41 @@
using System.Buffers;
using System.Text.Json;

namespace ZLogger
namespace ZLogger;
// Implement for log state.

public interface IZLoggerEntryCreatable
{
IZLoggerEntry CreateEntry(in LogInfo info);
}

public interface IZLoggerFormattable : IZLoggerEntryCreatable
{
int ParameterCount { get; }
bool IsSupportUtf8ParameterKey { get; }
string ToString();
void ToString(IBufferWriter<byte> writer);

void WriteJsonParameterKeyValues(Utf8JsonWriter jsonWriter, JsonSerializerOptions jsonSerializerOptions, IKeyNameMutator? keyNameMutator = null);

ReadOnlySpan<byte> GetParameterKey(int index);
string GetParameterKeyAsString(int index);
object? GetParameterValue(int index);
T? GetParameterValue<T>(int index);
Type GetParameterType(int index);

object? GetContext();
}

public interface IReferenceCountable
{
void Retain();
void Release();
}

public interface ICallerTracable
{
// Implement for log state.

public interface IZLoggerEntryCreatable
{
IZLoggerEntry CreateEntry(LogInfo info);
}

public interface IZLoggerFormattable : IZLoggerEntryCreatable
{
int ParameterCount { get; }
bool IsSupportUtf8ParameterKey { get; }
string ToString();
void ToString(IBufferWriter<byte> writer);

void WriteJsonParameterKeyValues(Utf8JsonWriter jsonWriter, JsonSerializerOptions jsonSerializerOptions, IKeyNameMutator? keyNameMutator = null);

ReadOnlySpan<byte> GetParameterKey(int index);
string GetParameterKeyAsString(int index);
object? GetParameterValue(int index);
T? GetParameterValue<T>(int index);
Type GetParameterType(int index);

object? GetContext();
}

public interface IReferenceCountable
{
void Retain();
void Release();
}
string? CallerMemberName { get; }
string? CallerFilePath { get; }
int CallerLineNumber { get; }
}
7 changes: 5 additions & 2 deletions src/ZLogger/LogInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@

namespace ZLogger;

public readonly struct LogInfo(LogCategory category, Timestamp timestamp, LogLevel logLevel, EventId eventId, Exception? exception, LogScopeState? scopeState)
public readonly struct LogInfo(LogCategory category, Timestamp timestamp, LogLevel logLevel, EventId eventId, Exception? exception, LogScopeState? scopeState, string? callerMemberName = null, string? callerFilePath = null, int callerLineNumber = 0)
{
public readonly LogCategory Category = category;
public readonly Timestamp Timestamp = timestamp;
public readonly LogLevel LogLevel = logLevel;
public readonly EventId EventId = eventId;
public readonly Exception? Exception = exception;
public readonly LogScopeState? ScopeState = scopeState;
public readonly string? CallerMemberName = callerMemberName;
public readonly string? CallerFilePath = callerFilePath;
public readonly int CallerLineNumber = callerLineNumber;
}

public readonly struct LogCategory
Expand All @@ -33,4 +36,4 @@ public override string ToString()
{
return Name;
}
}
}
Loading
Loading