diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Integration.Tests/Azure.Monitor.OpenTelemetry.AspNetCore.Integration.Tests.csproj b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Integration.Tests/Azure.Monitor.OpenTelemetry.AspNetCore.Integration.Tests.csproj
index 4d7ab15af3f60..8a2c6f076a4e8 100644
--- a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Integration.Tests/Azure.Monitor.OpenTelemetry.AspNetCore.Integration.Tests.csproj
+++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Integration.Tests/Azure.Monitor.OpenTelemetry.AspNetCore.Integration.Tests.csproj
@@ -11,6 +11,7 @@
+
diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Integration.Tests/DistroWebAppLiveTests.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Integration.Tests/DistroWebAppLiveTests.cs
index b27be2ad51cb0..6c7123d660994 100644
--- a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Integration.Tests/DistroWebAppLiveTests.cs
+++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Integration.Tests/DistroWebAppLiveTests.cs
@@ -14,6 +14,7 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using NUnit.Framework;
+using OpenTelemetry;
using OpenTelemetry.Logs;
using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;
@@ -25,11 +26,9 @@ namespace Azure.Monitor.OpenTelemetry.AspNetCore.Integration.Tests
{
public class DistroWebAppLiveTests : RecordedTestBase
{
- private const string TestServerUrl = "http://localhost:9998/";
-
- // DEVELOPER TIP: Change roleName to something unique when working locally (Example "Test##") to easily find your records.
- // Can search for all records in the portal via Log Analytics using this query: Union * | where AppRoleName == 'Test##'
- private const string RoleName = nameof(DistroWebAppLiveTests);
+ private const string TestServerPort = "9998";
+ private const string TestServerTarget = $"localhost:{TestServerPort}";
+ private const string TestServerUrl = $"http://{TestServerTarget}/";
private const string LogMessage = "Message via ILogger";
@@ -43,16 +42,9 @@ public DistroWebAppLiveTests(bool isAsync) : base(isAsync) { }
[SyncOnly] // This test cannot run concurrently with another test because OTel instruments the process and will cause side effects.
public async Task VerifyDistro()
{
+ var testStartTimeStamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffffffZ");
Console.WriteLine($"Integration test '{nameof(VerifyDistro)}' running in mode '{TestEnvironment.Mode}'");
- // DEVELOPER TIP: This test implicitly checks for telemetry within the last 30 minutes.
- // When working locally, this has the benefit of "priming" telemetry so that additional runs can complete faster without waiting for ingestion.
- // This can negatively impact the test results if you are debugging locally and making changes to the telemetry.
- // To mitigate this, you can include a timestamp in the query to only check for telemetry created since this test started.
- // IMPORTANT: we cannot include timestamps in the Recorded test because it breaks queries during playback.
- // C#: var testStartTimeStamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffffffZ");
- // QUERY: | where TimeGenerated >= datetime({ testStartTimeStamp})
-
// SETUP TELEMETRY CLIENT (FOR QUERYING LOG ANALYTICS)
_logsQueryClient = InstrumentClient(new LogsQueryClient(
TestEnvironment.LogsEndpoint,
@@ -66,9 +58,14 @@ public async Task VerifyDistro()
_logsQueryClient.SetQueryWorkSpaceId(TestEnvironment.WorkspaceId);
// SETUP WEBAPPLICATION WITH OPENTELEMETRY
+ string serviceName = "TestName", serviceNamespace = "TestNamespace", serviceInstance = "TestInstance", serviceVersion = "TestVersion";
+ string roleName = $"[{serviceNamespace}]/{serviceName}";
var resourceAttributes = new Dictionary
{
- { "service.name", RoleName },
+ { "service.name", serviceName },
+ { "service.namespace", serviceNamespace },
+ { "service.instance.id", serviceInstance },
+ { "service.version", serviceVersion }
};
var resourceBuilder = ResourceBuilder.CreateDefault();
@@ -81,13 +78,15 @@ public async Task VerifyDistro()
{
options.SetResourceBuilder(resourceBuilder);
});
+ builder.Services.ConfigureOpenTelemetryTracerProvider((sp, builder) => builder.AddProcessor(new ActivityEnrichingProcessor()));
builder.Services.AddOpenTelemetry()
- .ConfigureResource(x => x.AddAttributes(resourceAttributes))
.UseAzureMonitor(options =>
{
options.EnableLiveMetrics = false;
options.ConnectionString = TestEnvironment.ConnectionString;
- });
+ })
+ // Custom resources must be added AFTER AzureMonitor to override the included ResourceDetectors.
+ .ConfigureResource(x => x.AddAttributes(resourceAttributes));
var app = builder.Build();
app.MapGet("/", () =>
@@ -117,54 +116,120 @@ public async Task VerifyDistro()
// ASSERT
// NOTE: The following queries are using the LogAnalytics schema.
+
+ // DEVELOPER TIP: This test implicitly checks for telemetry within the last 30 minutes.
+ // When working locally, this has the benefit of "priming" telemetry so that additional runs can complete faster without waiting for ingestion.
+ // This can negatively impact the test results if you are debugging locally and making changes to the telemetry.
+ // To mitigate this, you can include a timestamp in the query to only check for telemetry created since this test started.
+ // IMPORTANT: we cannot include timestamps in the Recorded test because queries won't match during playback.
+ // C#: var testStartTimeStamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffffffZ");
+ // QUERY: | where TimeGenerated >= datetime({testStartTimeStamp})
+
await QueryAndVerifyDependency(
description: "Dependency for invoking HttpClient, from testhost",
- query: $"AppDependencies | where Data == '{TestServerUrl}' | where AppRoleName == '{RoleName}' | top 1 by TimeGenerated",
+ //query: $"AppDependencies | where Data == '{TestServerUrl}' | where AppRoleName == '{roleName}' | where TimeGenerated >= datetime({ testStartTimeStamp}) | top 1 by TimeGenerated",
+ query: $"AppDependencies | where Data == '{TestServerUrl}' | where AppRoleName == '{roleName}' | top 1 by TimeGenerated",
expectedAppDependency: new ExpectedAppDependency
{
+ Target = TestServerTarget,
+ DependencyType = "HTTP",
+ Name = "GET /",
Data = TestServerUrl,
- AppRoleName = RoleName,
+ Success = "True",
+ ResultCode = "200",
+ AppVersion = serviceVersion,
+ AppRoleName = roleName,
+ ClientIP = "0.0.0.0",
+ Type = "AppDependencies",
+ UserAuthenticatedId = "TestAuthenticatedUserId",
+ AppRoleInstance = serviceInstance,
+ Properties = new List>
+ {
+ new("_MS.ProcessedByMetricExtractors", "(Name: X,Ver:'1.1')"),
+ new("CustomProperty1", "Value1"),
+ },
});
await QueryAndVerifyRequest(
description: "RequestTelemetry, from WebApp",
- query: $"AppRequests | where Url == '{TestServerUrl}' | where AppRoleName == '{RoleName}' | top 1 by TimeGenerated",
+ //query: $"AppRequests | where Url == '{TestServerUrl}' | where AppRoleName == '{roleName}' | where TimeGenerated >= datetime({testStartTimeStamp}) | top 1 by TimeGenerated",
+ query: $"AppRequests | where Url == '{TestServerUrl}' | where AppRoleName == '{roleName}' | top 1 by TimeGenerated",
expectedAppRequest: new ExpectedAppRequest
{
Url = TestServerUrl,
- AppRoleName = RoleName,
+ AppRoleName = roleName,
+ Name = "GET /",
+ Success = "True",
+ ResultCode = "200",
+ OperationName = "GET /",
+ AppVersion = serviceVersion,
+ ClientIP = "0.0.0.0",
+ Type = "AppRequests",
+ UserAuthenticatedId = "TestAuthenticatedUserId",
+ AppRoleInstance = serviceInstance,
+ Properties = new List>
+ {
+ new("_MS.ProcessedByMetricExtractors", "(Name: X,Ver:'1.1')"),
+ new("CustomProperty1", "Value1"),
+ },
});
await QueryAndVerifyMetric(
description: "Metric for outgoing request, from testhost",
- query: $"AppMetrics | where Name == 'http.client.request.duration' | where AppRoleName == '{RoleName}' | where Properties.['server.address'] == 'localhost' | top 1 by TimeGenerated",
+ //query: $"AppMetrics | where Name == 'http.client.request.duration' | where AppRoleName == '{roleName}' | where Properties.['server.address'] == 'localhost' | where TimeGenerated >= datetime({testStartTimeStamp}) | top 1 by TimeGenerated",
+ query: $"AppMetrics | where Name == 'http.client.request.duration' | where AppRoleName == '{roleName}' | where Properties.['server.address'] == 'localhost' | top 1 by TimeGenerated",
expectedAppMetric: new ExpectedAppMetric
{
Name = "http.client.request.duration",
- AppRoleName = RoleName,
+ AppRoleName = roleName,
+ AppVersion = serviceVersion,
+ Type = "AppMetrics",
+ AppRoleInstance = serviceInstance,
Properties = new List>
{
+ new("http.request.method", "GET"),
+ new("http.response.status_code", "200"),
+ new("network.protocol.version", "1.1"),
new("server.address", "localhost"),
+ new("server.port", "9998"),
+ new("url.scheme", "http"),
},
});
await QueryAndVerifyMetric(
description: "Metric for incoming request, from WebApp",
- query: $"AppMetrics | where Name == 'http.server.request.duration' | where AppRoleName == '{RoleName}' | top 1 by TimeGenerated",
+ //query: $"AppMetrics | where Name == 'http.server.request.duration' | where AppRoleName == '{roleName}' | where TimeGenerated >= datetime({testStartTimeStamp}) | top 1 by TimeGenerated",
+ query: $"AppMetrics | where Name == 'http.server.request.duration' | where AppRoleName == '{roleName}' | top 1 by TimeGenerated",
expectedAppMetric: new ExpectedAppMetric
{
Name = "http.server.request.duration",
- AppRoleName = RoleName,
- Properties = new(),
+ AppRoleName = roleName,
+ AppVersion = serviceVersion,
+ Type = "AppMetrics",
+ AppRoleInstance = serviceInstance,
+ Properties = new List>
+ {
+ new("http.request.method", "GET"),
+ new("http.response.status_code", "200"),
+ new("http.route", "/"),
+ new("network.protocol.version", "1.1"),
+ new("url.scheme", "http")
+ }
});
await QueryAndVerifyTrace(
description: "ILogger LogInformation, from WebApp",
- query: $"AppTraces | where Message == '{LogMessage}' | where AppRoleName == '{RoleName}' | top 1 by TimeGenerated",
+ //query: $"AppTraces | where Message == '{LogMessage}' | where AppRoleName == '{roleName}' | where TimeGenerated >= datetime({testStartTimeStamp}) | top 1 by TimeGenerated",
+ query: $"AppTraces | where Message == '{LogMessage}' | where AppRoleName == '{roleName}' | top 1 by TimeGenerated",
expectedAppTrace: new ExpectedAppTrace
{
Message = LogMessage,
- AppRoleName = RoleName,
+ SeverityLevel = "1",
+ AppRoleName = roleName,
+ AppVersion = serviceVersion,
+ ClientIP = "0.0.0.0",
+ Type = "AppTraces",
+ AppRoleInstance = serviceInstance,
});
}
@@ -191,6 +256,15 @@ private async Task QueryAndVerifyTrace(string description, string query, Expecte
LogsTable? logsTable = await _logsQueryClient!.QueryTelemetryAsync(description, query);
ValidateExpectedTelemetry(description, logsTable, expectedAppTrace);
}
+
+ public class ActivityEnrichingProcessor : BaseProcessor
+ {
+ public override void OnEnd(Activity activity)
+ {
+ activity.SetTag("CustomProperty1", "Value1");
+ activity.SetTag("enduser.id", "TestAuthenticatedUserId");
+ }
+ }
}
}
#endif
diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Integration.Tests/SessionRecords/DistroWebAppLiveTests/VerifyDistro.json b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Integration.Tests/SessionRecords/DistroWebAppLiveTests/VerifyDistro.json
index aa039e05837a1..54c895dec01f7 100644
--- a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Integration.Tests/SessionRecords/DistroWebAppLiveTests/VerifyDistro.json
+++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Integration.Tests/SessionRecords/DistroWebAppLiveTests/VerifyDistro.json
@@ -6,15 +6,15 @@
"RequestHeaders": {
"Accept": "application/json",
"Authorization": "Sanitized",
- "Content-Length": "179",
+ "Content-Length": "182",
"Content-Type": "application/json",
- "traceparent": "00-c4516adafd33bcee5da05c3bcb37dd40-938a217833252e6f-00",
+ "traceparent": "00-bd93e9fb2d91a5a03fabf9633be9ea5e-12ca8fcea0ac5283-00",
"User-Agent": "azsdk-net-Monitor.Query/1.1.0 (.NET 7.0.20; Microsoft Windows 10.0.22631)",
"x-ms-client-request-id": "Sanitized",
"x-ms-return-client-request-id": "true"
},
"RequestBody": {
- "query": "AppDependencies | where Data == 'http://localhost:9998/' | where AppRoleName == 'DistroWebAppLiveTests' | top 1 by TimeGenerated",
+ "query": "AppDependencies | where Data == 'http://localhost:9998/' | where AppRoleName == '[TestNamespace]/TestName' | top 1 by TimeGenerated",
"timespan": "PT30M"
},
"StatusCode": 200,
@@ -22,12 +22,12 @@
"Access-Control-Allow-Origin": "*",
"Access-Control-Expose-Headers": "Retry-After,Age,WWW-Authenticate,x-resource-identities,x-ms-status-location",
"Connection": "keep-alive",
- "Content-Length": "2423",
+ "Content-Length": "2475",
"Content-Type": "application/json; charset=utf-8",
- "Date": "Fri, 07 Jun 2024 21:44:57 GMT",
+ "Date": "Thu, 13 Jun 2024 20:46:45 GMT",
"Strict-Transport-Security": "max-age=15724800; includeSubDomains",
"Vary": "Accept-Encoding",
- "Via": "1.1 draft-oms-84fccbf47-9zf5l",
+ "Via": "1.1 draft-oms-7b5b6f666d-hcnc8",
"X-Content-Type-Options": "nosniff"
},
"ResponseBody": {
@@ -203,29 +203,29 @@
"rows": [
[
"d49041ed-21aa-42c5-a6f3-6d60bb93d63c",
- "2024-06-07T21:44:23.1556457Z",
- "2f64853161967288",
+ "2024-06-13T20:41:12.3196552Z",
+ "f95c51aa6574bae5",
"localhost:9998",
"HTTP",
"GET /",
"http://localhost:9998/",
true,
"200",
- 81.8636,
+ 68.1025,
"<250ms",
- "{\"_MS.ProcessedByMetricExtractors\":\"(Name: X,Ver:'1.1')\"}",
+ "{\"CustomProperty1\":\"Value1\",\"_MS.ProcessedByMetricExtractors\":\"(Name: X,Ver:'1.1')\"}",
null,
"",
- "2f5dc72a16261a3a9e74e74ca0f3b4bf",
- "2f5dc72a16261a3a9e74e74ca0f3b4bf",
+ "986a2a0d5230df5f38c79666b260ea1b",
+ "986a2a0d5230df5f38c79666b260ea1b",
"",
"",
"",
+ "TestAuthenticatedUserId",
"",
- "",
- "",
- "DistroWebAppLiveTests",
- "af7c72ee-94a1-42f8-8306-395ce9147b22",
+ "TestVersion",
+ "[TestNamespace]/TestName",
+ "TestInstance",
"PC",
"Other",
"Windows 10",
@@ -236,7 +236,7 @@
"Other",
"8df423be-a013-477c-88b9-8186722e3d49",
"7b1ad079-51c6-4824-91c1-9decb485ba64",
- "dotnet7.0.20:otel1.8.1:ext1.3.0-beta.2-d",
+ "dotnet7.0.20:otel1.8.1:ext1.4.0-alpha.20240612-d",
1,
"",
"",
@@ -255,15 +255,15 @@
"RequestHeaders": {
"Accept": "application/json",
"Authorization": "Sanitized",
- "Content-Length": "174",
+ "Content-Length": "177",
"Content-Type": "application/json",
- "traceparent": "00-d90e7a2bf246528d5c75c004752cfefc-25dd917267728ea9-00",
+ "traceparent": "00-85f3606f8206cdd747e7ac6a7b9946e5-abd455fe22437ca3-00",
"User-Agent": "azsdk-net-Monitor.Query/1.1.0 (.NET 7.0.20; Microsoft Windows 10.0.22631)",
"x-ms-client-request-id": "Sanitized",
"x-ms-return-client-request-id": "true"
},
"RequestBody": {
- "query": "AppRequests | where Url == 'http://localhost:9998/' | where AppRoleName == 'DistroWebAppLiveTests' | top 1 by TimeGenerated",
+ "query": "AppRequests | where Url == 'http://localhost:9998/' | where AppRoleName == '[TestNamespace]/TestName' | top 1 by TimeGenerated",
"timespan": "PT30M"
},
"StatusCode": 200,
@@ -271,12 +271,12 @@
"Access-Control-Allow-Origin": "*",
"Access-Control-Expose-Headers": "Retry-After,Age,WWW-Authenticate,x-resource-identities,x-ms-status-location",
"Connection": "keep-alive",
- "Content-Length": "2392",
+ "Content-Length": "2444",
"Content-Type": "application/json; charset=utf-8",
- "Date": "Fri, 07 Jun 2024 21:44:58 GMT",
+ "Date": "Thu, 13 Jun 2024 20:46:48 GMT",
"Strict-Transport-Security": "max-age=15724800; includeSubDomains",
"Vary": "Accept-Encoding",
- "Via": "1.1 draft-oms-84fccbf47-vv6qb",
+ "Via": "1.1 draft-oms-7b5b6f666d-vdgs9",
"X-Content-Type-Options": "nosniff"
},
"ResponseBody": {
@@ -452,29 +452,29 @@
"rows": [
[
"d49041ed-21aa-42c5-a6f3-6d60bb93d63c",
- "2024-06-07T21:44:23.2035048Z",
- "52f6536389172c57",
+ "2024-06-13T20:41:12.3567089Z",
+ "37f332bbeadde96b",
"",
"GET /",
"http://localhost:9998/",
true,
"200",
- 33.8512,
+ 30.5704,
"<250ms",
- "{\"_MS.ProcessedByMetricExtractors\":\"(Name: X,Ver:'1.1')\"}",
+ "{\"CustomProperty1\":\"Value1\",\"_MS.ProcessedByMetricExtractors\":\"(Name: X,Ver:'1.1')\"}",
null,
"GET /",
- "2f5dc72a16261a3a9e74e74ca0f3b4bf",
+ "986a2a0d5230df5f38c79666b260ea1b",
null,
- "2f64853161967288",
- "",
- "",
+ "f95c51aa6574bae5",
"",
"",
"",
+ "TestAuthenticatedUserId",
"",
- "DistroWebAppLiveTests",
- "af7c72ee-94a1-42f8-8306-395ce9147b22",
+ "TestVersion",
+ "[TestNamespace]/TestName",
+ "TestInstance",
"PC",
"Other",
"Windows 10",
@@ -485,7 +485,7 @@
"Other",
"8df423be-a013-477c-88b9-8186722e3d49",
"7b1ad079-51c6-4824-91c1-9decb485ba64",
- "dotnet7.0.20:otel1.8.1:ext1.3.0-beta.2-d",
+ "dotnet7.0.20:otel1.8.1:ext1.4.0-alpha.20240612-d",
1,
"",
"",
@@ -504,15 +504,15 @@
"RequestHeaders": {
"Accept": "application/json",
"Authorization": "Sanitized",
- "Content-Length": "253",
+ "Content-Length": "256",
"Content-Type": "application/json",
- "traceparent": "00-cf77b2398e6b1a6ebf333d08dae5624f-5b6a30caa64b9b65-00",
+ "traceparent": "00-f0864b43407e78648bb376a3941c5547-a1d7de6f1b9e9b56-00",
"User-Agent": "azsdk-net-Monitor.Query/1.1.0 (.NET 7.0.20; Microsoft Windows 10.0.22631)",
"x-ms-client-request-id": "Sanitized",
"x-ms-return-client-request-id": "true"
},
"RequestBody": {
- "query": "AppMetrics | where Name == 'http.client.request.duration' | where AppRoleName == 'DistroWebAppLiveTests' | where Properties.['server.address'] == 'localhost' | top 1 by TimeGenerated",
+ "query": "AppMetrics | where Name == 'http.client.request.duration' | where AppRoleName == '[TestNamespace]/TestName' | where Properties.['server.address'] == 'localhost' | top 1 by TimeGenerated",
"timespan": "PT30M"
},
"StatusCode": 200,
@@ -522,10 +522,10 @@
"Connection": "keep-alive",
"Content-Length": "2097",
"Content-Type": "application/json; charset=utf-8",
- "Date": "Fri, 07 Jun 2024 21:44:58 GMT",
+ "Date": "Thu, 13 Jun 2024 20:46:48 GMT",
"Strict-Transport-Security": "max-age=15724800; includeSubDomains",
"Vary": "Accept-Encoding",
- "Via": "1.1 draft-oms-84fccbf47-9ff58",
+ "Via": "1.1 draft-oms-7b5b6f666d-2mhkm",
"X-Content-Type-Options": "nosniff"
},
"ResponseBody": {
@@ -669,13 +669,13 @@
"rows": [
[
"d49041ed-21aa-42c5-a6f3-6d60bb93d63c",
- "2024-06-07T21:44:23.41758Z",
+ "2024-06-13T20:41:12.5611815Z",
"http.client.request.duration",
1,
- 0.0818636,
- 0.0818636,
- 0.0818636,
- "{\"http.request.method\":\"GET\",\"http.response.status_code\":\"200\",\"network.protocol.version\":\"1.1\",\"server.address\":\"localhost\",\"server.port\":\"9998\",\"url.scheme\":\"http\"}",
+ 0.0681025,
+ 0.0681025,
+ 0.0681025,
+ "{\"http.request.method\":\"GET\",\"server.address\":\"localhost\",\"url.scheme\":\"http\",\"http.response.status_code\":\"200\",\"network.protocol.version\":\"1.1\",\"server.port\":\"9998\"}",
"",
"",
"",
@@ -684,9 +684,9 @@
"",
"",
"",
- "",
- "DistroWebAppLiveTests",
- "af7c72ee-94a1-42f8-8306-395ce9147b22",
+ "TestVersion",
+ "[TestNamespace]/TestName",
+ "TestInstance",
"PC",
"Other",
"Windows 10",
@@ -697,7 +697,7 @@
"Other",
"8df423be-a013-477c-88b9-8186722e3d49",
"7b1ad079-51c6-4824-91c1-9decb485ba64",
- "dotnet7.0.20:otel1.8.1:ext1.3.0-beta.2-d",
+ "dotnet7.0.20:otel1.8.1:ext1.4.0-alpha.20240612-d",
"Azure",
"AppMetrics",
"/subscriptions/65b2f83e-7bf1-4be3-bafc-3a4163265a52/resourcegroups/rg-tileemonitor/providers/microsoft.insights/components/t48da106dbe0b9268"
@@ -713,15 +713,15 @@
"RequestHeaders": {
"Accept": "application/json",
"Authorization": "Sanitized",
- "Content-Length": "180",
+ "Content-Length": "183",
"Content-Type": "application/json",
- "traceparent": "00-154cc7d705defc8173d6ade388684c0e-58f18a6b885d49f9-00",
+ "traceparent": "00-05cbb9ed28473cf5f9e0fd1fcc39f621-cc5792621b837c7f-00",
"User-Agent": "azsdk-net-Monitor.Query/1.1.0 (.NET 7.0.20; Microsoft Windows 10.0.22631)",
"x-ms-client-request-id": "Sanitized",
"x-ms-return-client-request-id": "true"
},
"RequestBody": {
- "query": "AppMetrics | where Name == 'http.server.request.duration' | where AppRoleName == 'DistroWebAppLiveTests' | top 1 by TimeGenerated",
+ "query": "AppMetrics | where Name == 'http.server.request.duration' | where AppRoleName == '[TestNamespace]/TestName' | top 1 by TimeGenerated",
"timespan": "PT30M"
},
"StatusCode": 200,
@@ -729,12 +729,12 @@
"Access-Control-Allow-Origin": "*",
"Access-Control-Expose-Headers": "Retry-After,Age,WWW-Authenticate,x-resource-identities,x-ms-status-location",
"Connection": "keep-alive",
- "Content-Length": "2062",
+ "Content-Length": "2060",
"Content-Type": "application/json; charset=utf-8",
- "Date": "Fri, 07 Jun 2024 21:45:00 GMT",
+ "Date": "Thu, 13 Jun 2024 20:46:49 GMT",
"Strict-Transport-Security": "max-age=15724800; includeSubDomains",
"Vary": "Accept-Encoding",
- "Via": "1.1 draft-oms-84fccbf47-z4b84",
+ "Via": "1.1 draft-oms-7b5b6f666d-xbjmt",
"X-Content-Type-Options": "nosniff"
},
"ResponseBody": {
@@ -878,14 +878,13 @@
"rows": [
[
"d49041ed-21aa-42c5-a6f3-6d60bb93d63c",
- "2024-06-07T21:44:23.4175451Z",
+ "2024-06-13T20:41:12.5611445Z",
"http.server.request.duration",
1,
- 0.0338512,
- 0.0338512,
- 0.0338512,
- "{\"http.request.method\":\"GET\",\"http.response.status_code\":\"200\",\"http.route\":\"/\",\"network.protocol.version\":\"1.1\",\"url.scheme\":\"http\"}",
- "",
+ 0.0305704,
+ 0.0305704,
+ 0.0305704,
+ "{\"http.route\":\"/\",\"http.request.method\":\"GET\",\"url.scheme\":\"http\",\"http.response.status_code\":\"200\",\"network.protocol.version\":\"1.1\"}",
"",
"",
"",
@@ -894,8 +893,9 @@
"",
"",
"",
- "DistroWebAppLiveTests",
- "af7c72ee-94a1-42f8-8306-395ce9147b22",
+ "TestVersion",
+ "[TestNamespace]/TestName",
+ "TestInstance",
"PC",
"Other",
"Windows 10",
@@ -906,7 +906,7 @@
"Other",
"8df423be-a013-477c-88b9-8186722e3d49",
"7b1ad079-51c6-4824-91c1-9decb485ba64",
- "dotnet7.0.20:otel1.8.1:ext1.3.0-beta.2-d",
+ "dotnet7.0.20:otel1.8.1:ext1.4.0-alpha.20240612-d",
"Azure",
"AppMetrics",
"/subscriptions/65b2f83e-7bf1-4be3-bafc-3a4163265a52/resourcegroups/rg-tileemonitor/providers/microsoft.insights/components/t48da106dbe0b9268"
@@ -922,15 +922,15 @@
"RequestHeaders": {
"Accept": "application/json",
"Authorization": "Sanitized",
- "Content-Length": "173",
+ "Content-Length": "176",
"Content-Type": "application/json",
- "traceparent": "00-9759964878634526a529cfa2071f06c9-0d03ec30c641be54-00",
+ "traceparent": "00-1026ff1d3d19f40039319c5ae263b712-1f07ea18488b7b43-00",
"User-Agent": "azsdk-net-Monitor.Query/1.1.0 (.NET 7.0.20; Microsoft Windows 10.0.22631)",
"x-ms-client-request-id": "Sanitized",
"x-ms-return-client-request-id": "true"
},
"RequestBody": {
- "query": "AppTraces | where Message == 'Message via ILogger' | where AppRoleName == 'DistroWebAppLiveTests' | top 1 by TimeGenerated",
+ "query": "AppTraces | where Message == 'Message via ILogger' | where AppRoleName == '[TestNamespace]/TestName' | top 1 by TimeGenerated",
"timespan": "PT30M"
},
"StatusCode": 200,
@@ -938,12 +938,12 @@
"Access-Control-Allow-Origin": "*",
"Access-Control-Expose-Headers": "Retry-After,Age,WWW-Authenticate,x-resource-identities,x-ms-status-location",
"Connection": "keep-alive",
- "Content-Length": "1989",
+ "Content-Length": "2011",
"Content-Type": "application/json; charset=utf-8",
- "Date": "Fri, 07 Jun 2024 21:45:01 GMT",
+ "Date": "Thu, 13 Jun 2024 20:46:50 GMT",
"Strict-Transport-Security": "max-age=15724800; includeSubDomains",
"Vary": "Accept-Encoding",
- "Via": "1.1 draft-oms-84fccbf47-q7zwk",
+ "Via": "1.1 draft-oms-7b5b6f666d-qjzzg",
"X-Content-Type-Options": "nosniff"
},
"ResponseBody": {
@@ -1091,22 +1091,22 @@
"rows": [
[
"d49041ed-21aa-42c5-a6f3-6d60bb93d63c",
- "2024-06-07T21:44:23.2335203Z",
+ "2024-06-13T20:41:12.3838321Z",
"Message via ILogger",
1,
null,
null,
"",
- "2f5dc72a16261a3a9e74e74ca0f3b4bf",
- "52f6536389172c57",
- "",
+ "986a2a0d5230df5f38c79666b260ea1b",
+ "37f332bbeadde96b",
"",
"",
"",
"",
"",
- "DistroWebAppLiveTests",
- "tilee-devbox",
+ "TestVersion",
+ "[TestNamespace]/TestName",
+ "TestInstance",
"PC",
"Other",
"Windows 10",
@@ -1117,7 +1117,7 @@
"Other",
"8df423be-a013-477c-88b9-8186722e3d49",
"7b1ad079-51c6-4824-91c1-9decb485ba64",
- "dotnet7.0.20:otel1.8.1:ext1.3.0-beta.2-d",
+ "dotnet7.0.20:otel1.8.1:ext1.4.0-alpha.20240612-d",
1,
"",
"",
@@ -1134,7 +1134,7 @@
"Variables": {
"CONNECTION_STRING": "InstrumentationKey=7b1ad079-51c6-4824-91c1-9decb485ba64;IngestionEndpoint=https://westus-0.in.applicationinsights.azure.com/;LiveEndpoint=https://westus.livediagnostics.monitor.azure.com/;ApplicationId=8df423be-a013-477c-88b9-8186722e3d49",
"LOGS_ENDPOINT": "https://api.loganalytics.io",
- "RandomSeed": "1564761728",
+ "RandomSeed": "1609645150",
"WORKSPACE_ID": "d49041ed-21aa-42c5-a6f3-6d60bb93d63c"
}
}
diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Integration.Tests/TelemetryValidationHelper.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Integration.Tests/TelemetryValidationHelper.cs
index 3628720bdb210..571e484bf2753 100644
--- a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Integration.Tests/TelemetryValidationHelper.cs
+++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Integration.Tests/TelemetryValidationHelper.cs
@@ -25,7 +25,7 @@ public static void ValidateExpectedTelemetry(string description, LogsTable? logs
{
if (property.Name == "Properties")
{
- var jsonString = row[property.Name].ToString();
+ var jsonString = row[property.Name]?.ToString();
Assert.IsNotNull(jsonString, $"({description}) Expected a non-null value for {property.Name}");
var expectedProperties = property.GetValue(expectedTelemetry, null) as List>;
Assert.IsNotNull(expectedProperties, $"({description}) Expected a non-null value for {nameof(expectedTelemetry)}.Properties");
@@ -37,11 +37,11 @@ public static void ValidateExpectedTelemetry(string description, LogsTable? logs
}
else
{
- TestContext.Out.WriteLine($"Property: '{property.Name}' ExpectedValue: '{property.GetValue(expectedTelemetry, null)}' ActualValue: '{row[property.Name]}'");
+ TestContext.Out.WriteLine($"PropertyName: '{property.Name}' ExpectedValue: '{property.GetValue(expectedTelemetry, null)}' ActualValue: '{row[property.Name]}'");
Assert.AreEqual(
- expected: property.GetValue(expectedTelemetry, null),
- actual: row[property.Name],
+ expected: property.GetValue(expectedTelemetry, null)!.ToString(),
+ actual: row[property.Name].ToString(),
message: $"({description}) Expected {property.Name} to be '{property.GetValue(expectedTelemetry, null)}' but found '{logsTable.Rows[0][property.Name]}'.");
}
}
@@ -55,6 +55,10 @@ private static void ValidateProperties(string description, string jsonString, Li
var jsonNode = JsonNode.Parse(jsonString);
Assert.IsNotNull(jsonNode, $"({description}) Expected a non-null JSON node.");
+ var expectedCount = expectedProperties.Count;
+ var actualCount = ((JsonObject)jsonNode!).Count;
+ Assert.AreEqual(expectedCount, actualCount, $"({description}) Expected {expectedCount} properties but found {actualCount}.");
+
foreach (var expectedProperty in expectedProperties)
{
var jsonValue = jsonNode![expectedProperty.Key];
@@ -71,37 +75,66 @@ private static void ValidateProperties(string description, string jsonString, Li
#endif
}
+ /*
+ * Notes on field validation:
+ * Remember that this test will be run as both a Recording and Live.
+ * We can't include unique ids becasue they are unique per test run (ie: Id, OperationId, ParentId, etc).
+ * We can't include timing fields because would be unique per test run(ie: TimeGenerated, DurationMS, PerformanceBucket).
+ * We can't include client fields because we can't control where these tests run (ie: ClientOS, ClientCity, ClientCountryOrRegion, etc).
+ */
+
public struct ExpectedAppDependency
{
+ public string Target { get; set; }
+ public string DependencyType { get; set; }
+ public string Name { get; set; }
public string Data { get; set; }
+ public string Success { get; set; }
+ public string ResultCode { get; set; }
+ public List> Properties { get; set; }
+ public string UserAuthenticatedId { get; set; }
+ public string AppVersion { get; set; }
public string AppRoleName { get; set; }
-
- // TODO: ADD REMAINING PROPERTIES IN FOLLOW UP PR.
+ public string AppRoleInstance { get; set; }
+ public string ClientIP { get; set; }
+ public string Type { get; set; }
}
public struct ExpectedAppRequest
{
+ public string Name { get; set; }
public string Url { get; set; }
+ public string Success { get; set; }
+ public string ResultCode { get; set; }
+ public List> Properties { get; set; }
+ public string OperationName { get; set; }
+ public string UserAuthenticatedId { get; set; }
+ public string AppVersion { get; set; }
public string AppRoleName { get; set; }
-
- // TODO: ADD REMAINING PROPERTIES IN FOLLOW UP PR.
+ public string AppRoleInstance { get; set; }
+ public string ClientIP { get; set; }
+ public string Type { get; set; }
}
public struct ExpectedAppMetric
{
public string Name { get; set; }
- public string AppRoleName { get; set; }
public List> Properties { get; set; }
-
- // TODO: ADD REMAINING PROPERTIES IN FOLLOW UP PR.
+ public string AppVersion { get; set; }
+ public string AppRoleName { get; set; }
+ public string AppRoleInstance { get; set; }
+ public string Type { get; set; }
}
public struct ExpectedAppTrace
{
public string Message { get; set; }
+ public string SeverityLevel { get; set; }
+ public string AppVersion { get; set; }
public string AppRoleName { get; set; }
-
- // TODO: ADD REMAINING PROPERTIES IN FOLLOW UP PR.
+ public string AppRoleInstance { get; set; }
+ public string ClientIP { get; set; }
+ public string Type { get; set; }
}
}
}