From 22dea3ba093bd7b44c2418212957cac5d4cfff98 Mon Sep 17 00:00:00 2001 From: Ryan Lamb <4955475+kinyoklion@users.noreply.github.com> Date: Fri, 3 Oct 2025 15:29:35 -0700 Subject: [PATCH 1/3] chore: Update log test scenarios. --- go/internal/otel/log-test-scenarios.json | 97 +++++++++++++++++++ .../log-test-scenarios.json | 97 +++++++++++++++++++ .../_otel/_sampling/log-test-scenarios.json | 97 +++++++++++++++++++ 3 files changed, 291 insertions(+) diff --git a/go/internal/otel/log-test-scenarios.json b/go/internal/otel/log-test-scenarios.json index 63b2a4acfe..f72530e506 100644 --- a/go/internal/otel/log-test-scenarios.json +++ b/go/internal/otel/log-test-scenarios.json @@ -420,5 +420,102 @@ } } ] + }, + { + "description": "Should not match an empty log when message and severity are defined", + "samplingConfig": { + "logs": [ + { + "message": { + "regexValue": "Database connection .*" + }, + "severityText": { + "matchValue": "error" + }, + "samplingRatio": 90 + } + ] + }, + "inputLog": {}, + "samplerFunctionCases": [ + { + "type": "always", + "expected_result": { + "sample": true + } + }, + { + "type": "never", + "expected_result": { + "sample": true + } + } + ] + }, + { + "description": "Should not match a log with a message when message and severity are defined", + "samplingConfig": { + "logs": [ + { + "message": { + "regexValue": "Database connection .*" + }, + "severityText": { + "matchValue": "error" + }, + "samplingRatio": 90 + } + ] + }, + "inputLog": { + "message": "Database connection failed: timeout" + }, + "samplerFunctionCases": [ + { + "type": "always", + "expected_result": { + "sample": true + } + }, + { + "type": "never", + "expected_result": { + "sample": true + } + } + ] + }, + { + "description": "Should not match a log with only severity when message and severity are defined", + "samplingConfig": { + "logs": [ + { + "message": { + "regexValue": "Database connection .*" + }, + "severityText": { + "matchValue": "error" + }, + "samplingRatio": 90 + } + ] + }, + "inputLog": { + "severityText": "error" + }, + "samplerFunctionCases": [ + { + "type": "always", + "expected_result": { + "sample": true + } + }, + { + "type": "never", + "expected_result": { + "sample": true + } + } + ] } ] diff --git a/sdk/@launchdarkly/observability-dotnet/test/LaunchDarkly.Observability.Tests/log-test-scenarios.json b/sdk/@launchdarkly/observability-dotnet/test/LaunchDarkly.Observability.Tests/log-test-scenarios.json index 97ec818f68..38efec42e6 100644 --- a/sdk/@launchdarkly/observability-dotnet/test/LaunchDarkly.Observability.Tests/log-test-scenarios.json +++ b/sdk/@launchdarkly/observability-dotnet/test/LaunchDarkly.Observability.Tests/log-test-scenarios.json @@ -388,5 +388,102 @@ } } ] + }, + { + "description": "Should not match an empty log when message and severity are defined", + "samplingConfig": { + "logs": [ + { + "message": { + "regexValue": "Database connection .*" + }, + "severityText": { + "matchValue": "error" + }, + "samplingRatio": 90 + } + ] + }, + "inputLog": {}, + "samplerFunctionCases": [ + { + "type": "always", + "expected_result": { + "sample": true + } + }, + { + "type": "never", + "expected_result": { + "sample": true + } + } + ] + }, + { + "description": "Should not match a log with a message when message and severity are defined", + "samplingConfig": { + "logs": [ + { + "message": { + "regexValue": "Database connection .*" + }, + "severityText": { + "matchValue": "error" + }, + "samplingRatio": 90 + } + ] + }, + "inputLog": { + "message": "Database connection failed: timeout" + }, + "samplerFunctionCases": [ + { + "type": "always", + "expected_result": { + "sample": true + } + }, + { + "type": "never", + "expected_result": { + "sample": true + } + } + ] + }, + { + "description": "Should not match a log with only severity when message and severity are defined", + "samplingConfig": { + "logs": [ + { + "message": { + "regexValue": "Database connection .*" + }, + "severityText": { + "matchValue": "error" + }, + "samplingRatio": 90 + } + ] + }, + "inputLog": { + "severityText": "error" + }, + "samplerFunctionCases": [ + { + "type": "always", + "expected_result": { + "sample": true + } + }, + { + "type": "never", + "expected_result": { + "sample": true + } + } + ] } ] diff --git a/sdk/@launchdarkly/observability-python/ldobserve/_otel/_sampling/log-test-scenarios.json b/sdk/@launchdarkly/observability-python/ldobserve/_otel/_sampling/log-test-scenarios.json index 28ea1dee01..dd0ea76112 100644 --- a/sdk/@launchdarkly/observability-python/ldobserve/_otel/_sampling/log-test-scenarios.json +++ b/sdk/@launchdarkly/observability-python/ldobserve/_otel/_sampling/log-test-scenarios.json @@ -388,5 +388,102 @@ } } ] + }, + { + "description": "Should not match an empty log when message and severity are defined", + "samplingConfig": { + "logs": [ + { + "message": { + "regexValue": "Database connection .*" + }, + "severityText": { + "matchValue": "error" + }, + "samplingRatio": 90 + } + ] + }, + "inputLog": {}, + "samplerFunctionCases": [ + { + "type": "always", + "expected_result": { + "sample": true + } + }, + { + "type": "never", + "expected_result": { + "sample": true + } + } + ] + }, + { + "description": "Should not match a log with a message when message and severity are defined", + "samplingConfig": { + "logs": [ + { + "message": { + "regexValue": "Database connection .*" + }, + "severityText": { + "matchValue": "error" + }, + "samplingRatio": 90 + } + ] + }, + "inputLog": { + "message": "Database connection failed: timeout" + }, + "samplerFunctionCases": [ + { + "type": "always", + "expected_result": { + "sample": true + } + }, + { + "type": "never", + "expected_result": { + "sample": true + } + } + ] + }, + { + "description": "Should not match a log with only severity when message and severity are defined", + "samplingConfig": { + "logs": [ + { + "message": { + "regexValue": "Database connection .*" + }, + "severityText": { + "matchValue": "error" + }, + "samplingRatio": 90 + } + ] + }, + "inputLog": { + "severityText": "error" + }, + "samplerFunctionCases": [ + { + "type": "always", + "expected_result": { + "sample": true + } + }, + { + "type": "never", + "expected_result": { + "sample": true + } + } + ] } ] From ffaec248f234970362dffda7c25234b82b4f7630 Mon Sep 17 00:00:00 2001 From: Ryan Lamb <4955475+kinyoklion@users.noreply.github.com> Date: Mon, 6 Oct 2025 12:59:36 -0700 Subject: [PATCH 2/3] Handle missing log level in .Net. --- .../LaunchDarkly.Observability/Otel/CommonOtelOptions.cs | 2 -- .../LaunchDarkly.Observability.Tests/CustomSamplerTests.cs | 6 ++++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sdk/@launchdarkly/observability-dotnet/src/LaunchDarkly.Observability/Otel/CommonOtelOptions.cs b/sdk/@launchdarkly/observability-dotnet/src/LaunchDarkly.Observability/Otel/CommonOtelOptions.cs index 3f765ada28..37cc019876 100644 --- a/sdk/@launchdarkly/observability-dotnet/src/LaunchDarkly.Observability/Otel/CommonOtelOptions.cs +++ b/sdk/@launchdarkly/observability-dotnet/src/LaunchDarkly.Observability/Otel/CommonOtelOptions.cs @@ -4,10 +4,8 @@ using System.Threading.Tasks; using LaunchDarkly.Observability.Logging; using LaunchDarkly.Observability.Sampling; -using LaunchDarkly.Sdk.Internal.Concurrent; using OpenTelemetry; using OpenTelemetry.Exporter; -using OpenTelemetry.Logs; using OpenTelemetry.Metrics; using OpenTelemetry.Resources; using OpenTelemetry.Trace; diff --git a/sdk/@launchdarkly/observability-dotnet/test/LaunchDarkly.Observability.Tests/CustomSamplerTests.cs b/sdk/@launchdarkly/observability-dotnet/test/LaunchDarkly.Observability.Tests/CustomSamplerTests.cs index f41ef0adb2..fbfbeef2e6 100644 --- a/sdk/@launchdarkly/observability-dotnet/test/LaunchDarkly.Observability.Tests/CustomSamplerTests.cs +++ b/sdk/@launchdarkly/observability-dotnet/test/LaunchDarkly.Observability.Tests/CustomSamplerTests.cs @@ -241,8 +241,10 @@ private LogLevel SeverityTextToLogLevel(string severityText) case null: return LogLevel.Information; default: - // Unsupported in this test suite. - throw new ArgumentOutOfRangeException(nameof(severityText), severityText, null); + // Log records cannot be made without a level, but in some languages they can, so we + // use "Information" for a missing level in the test suite. + // We cannot use "None" because the open telemetry logger is hard-coded to discard "None". + return LogLevel.Information; } } From 5e991a020f25edf430b6e1aca86858a2ed792496 Mon Sep 17 00:00:00 2001 From: Ryan Lamb <4955475+kinyoklion@users.noreply.github.com> Date: Mon, 6 Oct 2025 13:10:00 -0700 Subject: [PATCH 3/3] Check if attributes exists before checking if it is none. --- .../ldobserve/_otel/_sampling/test_custom_sampler.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/@launchdarkly/observability-python/ldobserve/_otel/_sampling/test_custom_sampler.py b/sdk/@launchdarkly/observability-python/ldobserve/_otel/_sampling/test_custom_sampler.py index 6070c199ad..9b6297aa89 100644 --- a/sdk/@launchdarkly/observability-python/ldobserve/_otel/_sampling/test_custom_sampler.py +++ b/sdk/@launchdarkly/observability-python/ldobserve/_otel/_sampling/test_custom_sampler.py @@ -177,7 +177,7 @@ def run_span_scenarios(): assert sampler.is_sampling_enabled() is True result = sampler.sample_span(span) assert result.sample == expected["sample"], desc - if expected["attributes"] is not None: + if "attributes" in expected and expected["attributes"] is not None: assert result.attributes == expected["attributes"], desc else: assert result.attributes is None or result.attributes == {}, desc @@ -202,7 +202,7 @@ def run_log_scenarios(): assert sampler.is_sampling_enabled() is True result = sampler.sample_log(log) assert result.sample == expected["sample"], desc - if expected["attributes"] is not None: + if "attributes" in expected and expected["attributes"] is not None: assert result.attributes == expected["attributes"], desc else: assert result.attributes is None or result.attributes == {}, desc