|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics;
using System.Threading.Channels;
using Aspire.Dashboard.Model.Otlp;
using Aspire.Dashboard.Otlp.Model;
using Aspire.Dashboard.Otlp.Storage;
using Aspire.Dashboard.Tests.Integration;
using Google.Protobuf.Collections;
using Microsoft.AspNetCore.InternalTesting;
using Microsoft.Extensions.Logging;
using OpenTelemetry.Proto.Logs.V1;
using Xunit;
using Xunit.Abstractions;
using static Aspire.Tests.Shared.Telemetry.TelemetryTestHelpers;
namespace Aspire.Dashboard.Tests.TelemetryRepositoryTests;
public class LogTests
{
private static readonly DateTime s_testTime = new(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
private readonly ITestOutputHelper _testOutputHelper;
public LogTests(ITestOutputHelper testOutputHelper)
{
_testOutputHelper = testOutputHelper;
}
[Fact]
public void AddLogs()
{
// Arrange
var repository = CreateRepository();
// Act
var addContext = new AddContext();
repository.AddLogs(addContext, new RepeatedField<ResourceLogs>()
{
new ResourceLogs
{
Resource = CreateResource(),
ScopeLogs =
{
new ScopeLogs
{
Scope = CreateScope("TestLogger"),
LogRecords = { CreateLogRecord() }
}
}
}
});
// Assert
Assert.Equal(0, addContext.FailureCount);
var applications = repository.GetApplications();
Assert.Collection(applications,
app =>
{
Assert.Equal("TestService", app.ApplicationName);
Assert.Equal("TestId", app.InstanceId);
});
var logs = repository.GetLogs(new GetLogsContext
{
ApplicationKey = applications[0].ApplicationKey,
StartIndex = 0,
Count = 10,
Filters = []
});
Assert.Collection(logs.Items,
app =>
{
Assert.Equal("546573745370616e4964", app.SpanId);
Assert.Equal("5465737454726163654964", app.TraceId);
Assert.Equal("Test {Log}", app.OriginalFormat);
Assert.Equal("Test Value!", app.Message);
Assert.Equal("TestLogger", app.Scope.ScopeName);
Assert.Collection(app.Attributes,
p =>
{
Assert.Equal("Log", p.Key);
Assert.Equal("Value!", p.Value);
});
});
var propertyKeys = repository.GetLogPropertyKeys(applications[0].ApplicationKey)!;
Assert.Collection(propertyKeys,
s => Assert.Equal("Log", s));
}
[Fact]
public void AddLogs_NoBody_EmptyMessage()
{
// Arrange
var repository = CreateRepository();
// Act
var addContext = new AddContext();
repository.AddLogs(addContext, new RepeatedField<ResourceLogs>()
{
new ResourceLogs
{
Resource = CreateResource(),
ScopeLogs =
{
new ScopeLogs
{
Scope = CreateScope("TestLogger"),
LogRecords = { CreateLogRecord(skipBody: true) }
}
}
}
});
// Assert
Assert.Equal(0, addContext.FailureCount);
var logs = repository.GetLogs(new GetLogsContext
{
ApplicationKey = null,
StartIndex = 0,
Count = 10,
Filters = []
});
Assert.Collection(logs.Items,
app =>
{
Assert.Equal("", app.Message);
});
}
[Fact]
public void AddLogs_MultipleOutOfOrder()
{
// Arrange
var repository = CreateRepository();
// Act
var addContext = new AddContext();
repository.AddLogs(addContext, new RepeatedField<ResourceLogs>()
{
new ResourceLogs
{
Resource = CreateResource(),
ScopeLogs =
{
new ScopeLogs
{
LogRecords =
{
CreateLogRecord(time: s_testTime.AddMinutes(1), message: "1"),
CreateLogRecord(time: s_testTime.AddMinutes(2), message: "2"),
CreateLogRecord(time: s_testTime.AddMinutes(3), message: "3"),
CreateLogRecord(time: s_testTime.AddMinutes(10), message: "10"),
CreateLogRecord(time: s_testTime.AddMinutes(9), message: "9"),
CreateLogRecord(time: s_testTime.AddMinutes(4), message: "4"),
CreateLogRecord(time: s_testTime.AddMinutes(5), message: "5"),
CreateLogRecord(time: s_testTime.AddMinutes(7), message: "7"),
CreateLogRecord(time: s_testTime.AddMinutes(6), message: "6"),
CreateLogRecord(time: s_testTime.AddMinutes(8), message: "8"),
}
}
}
}
});
// Assert
Assert.Equal(0, addContext.FailureCount);
var logs = repository.GetLogs(new GetLogsContext
{
ApplicationKey = null,
StartIndex = 0,
Count = 10,
Filters = []
});
Assert.Collection(logs.Items,
l =>
{
Assert.Equal("1", l.Message);
Assert.Equal("", l.Scope.ScopeName);
},
l => Assert.Equal("2", l.Message),
l => Assert.Equal("3", l.Message),
l => Assert.Equal("4", l.Message),
l => Assert.Equal("5", l.Message),
l => Assert.Equal("6", l.Message),
l => Assert.Equal("7", l.Message),
l => Assert.Equal("8", l.Message),
l => Assert.Equal("9", l.Message),
l => Assert.Equal("10", l.Message));
}
[Fact]
public void AddLogs_Error_UnviewedCount()
{
// Arrange
var repository = CreateRepository();
// Act
var addContext = new AddContext();
repository.AddLogs(addContext, new RepeatedField<ResourceLogs>()
{
new ResourceLogs
{
Resource = CreateResource(instanceId: "1"),
ScopeLogs =
{
new ScopeLogs
{
Scope = CreateScope("TestLogger"),
LogRecords =
{
CreateLogRecord(time: s_testTime.AddMinutes(1), message: "1", severity: SeverityNumber.Trace),
CreateLogRecord(time: s_testTime.AddMinutes(2), message: "2", severity: SeverityNumber.Debug),
CreateLogRecord(time: s_testTime.AddMinutes(3), message: "3", severity: SeverityNumber.Info),
CreateLogRecord(time: s_testTime.AddMinutes(4), message: "4", severity: SeverityNumber.Warn),
CreateLogRecord(time: s_testTime.AddMinutes(5), message: "5", severity: SeverityNumber.Error),
CreateLogRecord(time: s_testTime.AddMinutes(6), message: "6", severity: SeverityNumber.Fatal)
}
}
}
},
new ResourceLogs
{
Resource = CreateResource(instanceId: "2"),
ScopeLogs =
{
new ScopeLogs
{
Scope = CreateScope("TestLogger"),
LogRecords =
{
CreateLogRecord(time: s_testTime.AddMinutes(1), message: "1", severity: SeverityNumber.Fatal)
}
}
}
}
});
// Assert
Assert.Equal(0, addContext.FailureCount);
var unviewedCounts1 = repository.GetApplicationUnviewedErrorLogsCount();
Assert.True(unviewedCounts1.TryGetValue(new ApplicationKey("TestService", "1"), out var unviewedCount1));
Assert.Equal(2, unviewedCount1);
Assert.True(unviewedCounts1.TryGetValue(new ApplicationKey("TestService", "2"), out var unviewedCount2));
Assert.Equal(1, unviewedCount2);
repository.MarkViewedErrorLogs(new ApplicationKey("TestService", "1"));
var unviewedCounts2 = repository.GetApplicationUnviewedErrorLogsCount();
Assert.False(unviewedCounts2.TryGetValue(new ApplicationKey("TestService", "1"), out _));
Assert.True(unviewedCounts2.TryGetValue(new ApplicationKey("TestService", "2"), out unviewedCount2));
Assert.Equal(1, unviewedCount2);
repository.MarkViewedErrorLogs(null);
var unviewedCounts3 = repository.GetApplicationUnviewedErrorLogsCount();
Assert.False(unviewedCounts3.TryGetValue(new ApplicationKey("TestService", "1"), out _));
Assert.False(unviewedCounts3.TryGetValue(new ApplicationKey("TestService", "2"), out _));
}
[Fact]
public void AddLogs_Error_UnviewedCount_WithReadSubscriptionAll()
{
// Arrange
var repository = CreateRepository();
using var subscription = repository.OnNewLogs(applicationKey: null, SubscriptionType.Read, () => Task.CompletedTask);
// Act
var addContext = new AddContext();
repository.AddLogs(addContext, new RepeatedField<ResourceLogs>()
{
new ResourceLogs
{
Resource = CreateResource(instanceId: "1"),
ScopeLogs =
{
new ScopeLogs
{
Scope = CreateScope("TestLogger"),
LogRecords =
{
CreateLogRecord(time: s_testTime.AddMinutes(1), message: "1", severity: SeverityNumber.Error),
}
}
}
},
new ResourceLogs
{
Resource = CreateResource(instanceId: "2"),
ScopeLogs =
{
new ScopeLogs
{
Scope = CreateScope("TestLogger"),
LogRecords =
{
CreateLogRecord(time: s_testTime.AddMinutes(1), message: "1", severity: SeverityNumber.Fatal)
}
}
}
}
});
// Assert
Assert.Equal(0, addContext.FailureCount);
var unviewedCounts = repository.GetApplicationUnviewedErrorLogsCount();
Assert.False(unviewedCounts.TryGetValue(new ApplicationKey("TestService", "1"), out _));
Assert.False(unviewedCounts.TryGetValue(new ApplicationKey("TestService", "2"), out _));
}
[Fact]
public void AddLogs_Error_UnviewedCount_WithReadSubscriptionOneApp()
{
// Arrange
var repository = CreateRepository();
using var subscription = repository.OnNewLogs(applicationKey: new ApplicationKey("TestService", "1"), SubscriptionType.Read, () => Task.CompletedTask);
// Act
var addContext = new AddContext();
repository.AddLogs(addContext, new RepeatedField<ResourceLogs>()
{
new ResourceLogs
{
Resource = CreateResource(instanceId: "1"),
ScopeLogs =
{
new ScopeLogs
{
Scope = CreateScope("TestLogger"),
LogRecords =
{
CreateLogRecord(time: s_testTime.AddMinutes(1), message: "1", severity: SeverityNumber.Error),
}
}
}
},
new ResourceLogs
{
Resource = CreateResource(instanceId: "2"),
ScopeLogs =
{
new ScopeLogs
{
Scope = CreateScope("TestLogger"),
LogRecords =
{
CreateLogRecord(time: s_testTime.AddMinutes(1), message: "1", severity: SeverityNumber.Fatal)
}
}
}
}
});
// Assert
Assert.Equal(0, addContext.FailureCount);
var unviewedCounts = repository.GetApplicationUnviewedErrorLogsCount();
Assert.False(unviewedCounts.TryGetValue(new ApplicationKey("TestService", "1"), out _));
Assert.True(unviewedCounts.TryGetValue(new ApplicationKey("TestService", "2"), out var unviewedCount));
Assert.Equal(1, unviewedCount);
}
[Fact]
public void AddLogs_Error_UnviewedCount_WithNonReadSubscription()
{
// Arrange
var repository = CreateRepository();
using var subscription = repository.OnNewLogs(applicationKey: null, SubscriptionType.Other, () => Task.CompletedTask);
// Act
var addContext = new AddContext();
repository.AddLogs(addContext, new RepeatedField<ResourceLogs>()
{
new ResourceLogs
{
Resource = CreateResource(instanceId: "1"),
ScopeLogs =
{
new ScopeLogs
{
Scope = CreateScope("TestLogger"),
LogRecords =
{
CreateLogRecord(time: s_testTime.AddMinutes(1), message: "1", severity: SeverityNumber.Error),
}
}
}
}
});
// Assert
Assert.Equal(0, addContext.FailureCount);
var unviewedCounts = repository.GetApplicationUnviewedErrorLogsCount();
Assert.True(unviewedCounts.TryGetValue(new ApplicationKey("TestService", "1"), out var unviewedCount));
Assert.Equal(1, unviewedCount);
}
[Fact]
public void GetLogs_UnknownApplication()
{
// Arrange
var repository = CreateRepository();
// Act
var logs = repository.GetLogs(new GetLogsContext
{
ApplicationKey = new ApplicationKey("TestService", "UnknownApplication"),
StartIndex = 0,
Count = 10,
Filters = []
});
// Assert
Assert.Empty(logs.Items);
}
[Fact]
public void GetLogPropertyKeys_UnknownApplication()
{
// Arrange
var repository = CreateRepository();
// Act
var propertyKeys = repository.GetLogPropertyKeys(new ApplicationKey("TestService", "UnknownApplication"));
// Assert
Assert.Empty(propertyKeys);
}
[Fact]
public async Task Subscriptions_AddLog()
{
// Arrange
var repository = CreateRepository();
var newApplicationsTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
repository.OnNewApplications(() =>
{
newApplicationsTcs.TrySetResult();
return Task.CompletedTask;
});
// Act 1
var addContext1 = new AddContext();
repository.AddLogs(addContext1, new RepeatedField<ResourceLogs>()
{
new ResourceLogs
{
Resource = CreateResource(),
ScopeLogs =
{
new ScopeLogs
{
Scope = CreateScope("TestLogger"),
LogRecords = { CreateLogRecord() }
}
}
}
});
// Assert 1
Assert.Equal(0, addContext1.FailureCount);
await newApplicationsTcs.Task.DefaultTimeout();
var applications = repository.GetApplications();
Assert.Collection(applications,
app =>
{
Assert.Equal("TestService", app.ApplicationName);
Assert.Equal("TestId", app.InstanceId);
});
// Act 2
var newLogsTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
repository.OnNewLogs(applications[0].ApplicationKey, SubscriptionType.Read, () =>
{
newLogsTcs.TrySetResult();
return Task.CompletedTask;
});
var addContext2 = new AddContext();
repository.AddLogs(addContext2, new RepeatedField<ResourceLogs>()
{
new ResourceLogs
{
Resource = CreateResource(),
ScopeLogs =
{
new ScopeLogs
{
Scope = CreateScope("TestLogger"),
LogRecords = { CreateLogRecord() }
}
}
}
});
await newLogsTcs.Task.DefaultTimeout();
// Assert 2
Assert.Equal(0, addContext2.FailureCount);
var logs = repository.GetLogs(new GetLogsContext
{
ApplicationKey = applications[0].ApplicationKey,
StartIndex = 0,
Count = 1,
Filters = []
})!;
Assert.Single(logs.Items);
Assert.Equal(2, logs.TotalItemCount);
}
[Fact]
public void Unsubscribe()
{
// Arrange
var repository = CreateRepository();
var onNewApplicationsCalled = false;
var subscription = repository.OnNewApplications(() =>
{
onNewApplicationsCalled = true;
return Task.CompletedTask;
});
subscription.Dispose();
// Act
var addContext = new AddContext();
repository.AddLogs(addContext, new RepeatedField<ResourceLogs>()
{
new ResourceLogs
{
Resource = CreateResource(),
ScopeLogs =
{
new ScopeLogs
{
Scope = CreateScope("TestLogger"),
LogRecords = { CreateLogRecord() }
}
}
}
});
// Assert
Assert.Equal(0, addContext.FailureCount);
Assert.False(onNewApplicationsCalled, "Callback shouldn't have been called because subscription was disposed.");
}
[Fact]
public async Task Subscription_RaisedFromDifferentContext_InitialContextPreserved()
{
// Arrange
var asyncLocal = new AsyncLocal<string>();
asyncLocal.Value = "CustomValue";
var repository = CreateRepository();
var tcs = new TaskCompletionSource<string>(TaskCreationOptions.RunContinuationsAsynchronously);
var subscription = repository.OnNewApplications(() =>
{
tcs.SetResult(asyncLocal.Value);
return Task.CompletedTask;
});
// Act
Task task;
using (ExecutionContext.SuppressFlow())
{
task = Task.Run(() =>
{
var addContext = new AddContext();
repository.AddLogs(addContext, new RepeatedField<ResourceLogs>()
{
new ResourceLogs
{
Resource = CreateResource(),
ScopeLogs =
{
new ScopeLogs
{
Scope = CreateScope("TestLogger"),
LogRecords = { CreateLogRecord() }
}
}
}
});
});
}
await task.DefaultTimeout();
// Assert
var callbackValue = await tcs.Task.DefaultTimeout();
Assert.Equal("CustomValue", callbackValue);
}
[Fact]
public void AddLogs_AttributeLimits_LimitsApplied()
{
// Arrange
var repository = CreateRepository(maxAttributeCount: 5, maxAttributeLength: 16);
// Act
var attributes = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("{OriginalFormat}", "Test {Log}")
};
for (var i = 0; i < 10; i++)
{
var value = GetValue((i + 1) * 5);
attributes.Add(new KeyValuePair<string, string>($"Key{i}", value));
}
var addContext = new AddContext();
repository.AddLogs(addContext, new RepeatedField<ResourceLogs>()
{
new ResourceLogs
{
Resource = CreateResource(),
ScopeLogs =
{
new ScopeLogs
{
Scope = CreateScope("TestLogger"),
LogRecords = { CreateLogRecord(message: GetValue(50), attributes: attributes) }
}
}
}
});
// Assert
Assert.Equal(0, addContext.FailureCount);
var applications = repository.GetApplications();
Assert.Collection(applications,
app =>
{
Assert.Equal("TestService", app.ApplicationName);
Assert.Equal("TestId", app.InstanceId);
});
var logs = repository.GetLogs(new GetLogsContext
{
ApplicationKey = applications[0].ApplicationKey,
StartIndex = 0,
Count = 10,
Filters = []
});
Assert.Collection(logs.Items,
app =>
{
Assert.Equal("Test {Log}", app.OriginalFormat);
Assert.Equal("0123456789012345", app.Message);
Assert.Collection(app.Attributes,
p =>
{
Assert.Equal("Key0", p.Key);
Assert.Equal("01234", p.Value);
},
p =>
{
Assert.Equal("Key1", p.Key);
Assert.Equal("0123456789", p.Value);
},
p =>
{
Assert.Equal("Key2", p.Key);
Assert.Equal("012345678901234", p.Value);
},
p =>
{
Assert.Equal("Key3", p.Key);
Assert.Equal("0123456789012345", p.Value);
},
p =>
{
Assert.Equal("Key4", p.Key);
Assert.Equal("0123456789012345", p.Value);
});
});
}
[Fact]
public async Task Subscription_MultipleUpdates_MinExecuteIntervalApplied()
{
// Arrange
var minExecuteInterval = TimeSpan.FromMilliseconds(500);
var loggerFactory = IntegrationTestHelpers.CreateLoggerFactory(_testOutputHelper);
var logger = loggerFactory.CreateLogger(nameof(LogTests));
var repository = CreateRepository(subscriptionMinExecuteInterval: minExecuteInterval, loggerFactory: loggerFactory);
var stopwatch = new Stopwatch();
var callCount = 0;
var resultChannel = Channel.CreateUnbounded<int>();
var subscription = repository.OnNewLogs(applicationKey: null, SubscriptionType.Read, async () =>
{
if (!stopwatch.IsRunning)
{
stopwatch.Start();
}
else
{
stopwatch.Stop();
}
++callCount;
resultChannel.Writer.TryWrite(callCount);
await Task.Delay(20);
});
// Act
var addContext = new AddContext();
logger.LogInformation("Writing log 1");
repository.AddLogs(addContext, new RepeatedField<ResourceLogs>()
{
new ResourceLogs
{
Resource = CreateResource(),
ScopeLogs =
{
new ScopeLogs
{
Scope = CreateScope("TestLogger"),
LogRecords = { CreateLogRecord() }
}
}
}
});
// Assert
var read1 = await resultChannel.Reader.ReadAsync().DefaultTimeout();
Assert.Equal(1, read1);
logger.LogInformation("Received log 1 callback");
logger.LogInformation("Writing log 2");
repository.AddLogs(addContext, new RepeatedField<ResourceLogs>()
{
new ResourceLogs
{
Resource = CreateResource(),
ScopeLogs =
{
new ScopeLogs
{
Scope = CreateScope("TestLogger"),
LogRecords = { CreateLogRecord() }
}
}
}
});
var read2 = await resultChannel.Reader.ReadAsync().DefaultTimeout();
Assert.Equal(2, read2);
logger.LogInformation("Received log 2 callback");
var elapsed = stopwatch.Elapsed;
logger.LogInformation("Elapsed time: {Elapsed}", elapsed);
CustomAssert.AssertExceedsMinInterval(elapsed, minExecuteInterval);
}
[Fact]
public void FilterLogs_With_Message_Returns_CorrectLog()
{
// Arrange
var repository = CreateRepository();
// Act
var addContext = new AddContext();
repository.AddLogs(addContext, new RepeatedField<ResourceLogs>()
{
new ResourceLogs
{
Resource = CreateResource(instanceId: "1"),
ScopeLogs =
{
new ScopeLogs
{
Scope = CreateScope("TestLogger"),
LogRecords =
{
CreateLogRecord(time: s_testTime.AddMinutes(1), message: "test_message", severity: SeverityNumber.Error),
}
}
}
}
});
var applicationKey = repository.GetApplications().First().ApplicationKey;
// Assert
Assert.Empty(repository.GetLogs(new GetLogsContext
{
ApplicationKey = applicationKey,
StartIndex = 0,
Count = 1,
Filters = [new TelemetryFilter { Condition = FilterCondition.Contains, Field = nameof(OtlpLogEntry.Message), Value = "does_not_contain" }]
}).Items);
Assert.Single(repository.GetLogs(new GetLogsContext
{
ApplicationKey = applicationKey,
StartIndex = 0,
Count = 1,
Filters = [new TelemetryFilter { Condition = FilterCondition.Contains, Field = nameof(OtlpLogEntry.Message), Value = "message" }]
}).Items);
}
[Fact]
public void AddLogs_MultipleResources_SameInstanceId_CreateMultipleResources()
{
// Arrange
var repository = CreateRepository();
// Act
var addContext = new AddContext();
repository.AddLogs(addContext, new RepeatedField<ResourceLogs>()
{
new ResourceLogs
{
Resource = CreateResource(name: "App1", instanceId: "computer-name"),
ScopeLogs =
{
new ScopeLogs
{
Scope = CreateScope("TestLogger"),
LogRecords = { CreateLogRecord() }
}
}
},
new ResourceLogs
{
Resource = CreateResource(name: "App2", instanceId: "computer-name"),
ScopeLogs =
{
new ScopeLogs
{
Scope = CreateScope("TestLogger"),
LogRecords = { CreateLogRecord() }
}
}
}
});
// Assert
Assert.Equal(0, addContext.FailureCount);
var applications = repository.GetApplications();
Assert.Collection(applications,
app =>
{
Assert.Equal("App1", app.ApplicationName);
Assert.Equal("computer-name", app.InstanceId);
},
app =>
{
Assert.Equal("App2", app.ApplicationName);
Assert.Equal("computer-name", app.InstanceId);
});
var logs1 = repository.GetLogs(new GetLogsContext
{
ApplicationKey = applications[0].ApplicationKey,
StartIndex = 0,
Count = 10,
Filters = []
});
Assert.Collection(logs1.Items,
app =>
{
Assert.Equal("546573745370616e4964", app.SpanId);
Assert.Equal("5465737454726163654964", app.TraceId);
Assert.Equal("Test {Log}", app.OriginalFormat);
Assert.Equal("Test Value!", app.Message);
Assert.Equal("TestLogger", app.Scope.ScopeName);
Assert.Collection(app.Attributes,
p =>
{
Assert.Equal("Log", p.Key);
Assert.Equal("Value!", p.Value);
});
});
var logs2 = repository.GetLogs(new GetLogsContext
{
ApplicationKey = applications[1].ApplicationKey,
StartIndex = 0,
Count = 10,
Filters = []
});
Assert.Collection(logs2.Items,
app =>
{
Assert.Equal("546573745370616e4964", app.SpanId);
Assert.Equal("5465737454726163654964", app.TraceId);
Assert.Equal("Test {Log}", app.OriginalFormat);
Assert.Equal("Test Value!", app.Message);
Assert.Equal("TestLogger", app.Scope.ScopeName);
Assert.Collection(app.Attributes,
p =>
{
Assert.Equal("Log", p.Key);
Assert.Equal("Value!", p.Value);
});
});
}
[Fact]
public void GetLogs_MultipleInstances()
{
// Arrange
var repository = CreateRepository();
// Act
var addContext = new AddContext();
repository.AddLogs(addContext, new RepeatedField<ResourceLogs>()
{
new ResourceLogs
{
Resource = CreateResource(name: "app1", instanceId: "123"),
ScopeLogs =
{
new ScopeLogs
{
Scope = CreateScope("TestLogger"),
LogRecords = { CreateLogRecord(time: s_testTime.AddMinutes(1), message: "message-1", attributes: [KeyValuePair.Create("key-1", "value-1")]) }
}
}
},
new ResourceLogs
{
Resource = CreateResource(name: "app1", instanceId: "456"),
ScopeLogs =
{
new ScopeLogs
{
Scope = CreateScope("TestLogger"),
LogRecords = { CreateLogRecord(time: s_testTime.AddMinutes(2), message: "message-2", attributes: [KeyValuePair.Create("key-2", "value-2")]) }
}
}
},
new ResourceLogs
{
Resource = CreateResource(name: "app2"),
ScopeLogs =
{
new ScopeLogs
{
Scope = CreateScope("TestLogger"),
LogRecords = { CreateLogRecord(time: s_testTime.AddMinutes(3)) }
}
}
}
});
// Assert
Assert.Equal(0, addContext.FailureCount);
var appKey = new ApplicationKey("app1", InstanceId: null);
var logs = repository.GetLogs(new GetLogsContext
{
ApplicationKey = appKey,
StartIndex = 0,
Count = 10,
Filters = []
});
Assert.Collection(logs.Items,
app =>
{
Assert.Equal("message-1", app.Message);
Assert.Equal("TestLogger", app.Scope.ScopeName);
Assert.Collection(app.Attributes,
p =>
{
Assert.Equal("key-1", p.Key);
Assert.Equal("value-1", p.Value);
});
},
app =>
{
Assert.Equal("message-2", app.Message);
Assert.Equal("TestLogger", app.Scope.ScopeName);
Assert.Collection(app.Attributes,
p =>
{
Assert.Equal("key-2", p.Key);
Assert.Equal("value-2", p.Value);
});
});
var propertyKeys = repository.GetLogPropertyKeys(appKey)!;
Assert.Collection(propertyKeys,
s => Assert.Equal("key-1", s),
s => Assert.Equal("key-2", s));
}
}
|