Skip to main content

Test Scenarios for Sovdev Logger

Overview

This document defines the required test scenarios that all sovdev-logger implementations MUST pass. These tests verify that implementations produce correct output across all three transports (OTLP, console, file) and that the observability stack properly receives and stores the data.


⚡ Quick Start: Testing Your Implementation

IMPORTANT: Use the provided tools in tools/validation/uis/ - DO NOT create custom validation scripts!

Testing Process

All sovdev-logger implementations are tested the same way, regardless of language:

Step 1: Test log files

# Validate log file format (fast, local-only test)
./tools/validation/uis/validate-log-format.sh {language}/test/e2e/company-lookup/logs/dev.log

Step 2: Test OTLP export (exact match, not just presence)

LOG_FILE="{language}/test/e2e/company-lookup/logs/dev.log"
./tools/validation/uis/query-loki.sh sovdev-test-company-lookup-{language} --compare-with "$LOG_FILE"
./tools/validation/uis/query-tempo.sh sovdev-test-company-lookup-{language} --compare-with "$LOG_FILE"
./tools/validation/uis/query-prometheus.sh sovdev-test-company-lookup-{language} --compare-with "$LOG_FILE"

Step 3: Cross-language conformance (the completion gate)

./tools/validation/uis/compare-with-master.sh {language}

Example Workflow

# TypeScript implementation
./tools/validation/uis/validate-log-format.sh typescript/test/e2e/company-lookup/logs/dev.log
./tools/validation/uis/run-company-lookup.sh typescript
./tools/validation/uis/compare-with-master.sh typescript

# Python implementation
./tools/validation/uis/validate-log-format.sh python/test/e2e/company-lookup/logs/dev.log
./tools/validation/uis/run-company-lookup.sh python
./tools/validation/uis/compare-with-master.sh python

Why Use These Tools?

  • Language-agnostic: Works identically for all implementations
  • Comprehensive: Tests file output, OTLP export, and backend verification
  • Automated: No manual steps or Grafana clicking required
  • Consistent: Same verification process for all languages

📚 For complete tool documentation, see tools/validation/uis/README.md (authoritative source)

📝 For detailed company-lookup test specification, see 08-testprogram-company-lookup.md


Required Project Structure

All sovdev-logger implementations MUST follow this standardized directory structure:

{language}/
├── Makefile # Consistent interface (optional but recommended)
├── src/ # Source code (implementation-specific)
├── test/
│ ├── unit/ # Unit tests (language-specific framework)
│ ├── integration/ # Integration tests (language-specific)
│ └── e2e/
│ └── company-lookup/ # ⚠️ REQUIRED - Used by verification tools
│ ├── run-test.sh # Entry point script (MUST exist)
│ ├── company-lookup.* # E2E test implementation
│ ├── .env # OTLP configuration (MUST exist)
│ └── logs/ # Test output directory

Critical Requirements

1. Standardized Path

  • All languages MUST use test/e2e/company-lookup/ exactly
  • This enables language-agnostic verification tools
  • Verification scripts and templates depend on this convention

2. run-test.sh Script (MUST EXIST)

  • REQUIRED file - Entry point for running the full-stack E2E test
  • Loads .env configuration (also REQUIRED)
  • Executes language-specific test command (e.g., python3 company-lookup.py, npx tsx company-lookup.ts)
  • Returns exit code (0=success, non-zero=failure)

3. company-lookup. Test*

  • Comprehensive E2E test covering all 11 test scenarios
  • Uses real OTLP endpoints (sends to Loki, Prometheus, Tempo)
  • Demonstrates best practices (FUNCTIONNAME constant, variable reuse, etc.)
  • File extension matches language (.py, .ts, .go, .java, etc.)

4. .env Configuration (MUST EXIST)

  • REQUIRED file - MUST be present in test/e2e/company-lookup/.env
  • Contains OTLP endpoint URLs and configuration
  • Format: KEY=value (standard shell format)
  • Example:
    SYSTEM_ID=sovdev-test-company-lookup-{language}
    OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=http://127.0.0.1/v1/logs
    OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=http://127.0.0.1/v1/metrics
    OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://127.0.0.1/v1/traces
    OTEL_EXPORTER_OTLP_HEADERS=Host=otel.localhost

Note: OTEL_EXPORTER_OTLP_HEADERS is the standard OpenTelemetry format — comma-separated key=value pairs, not JSON (see INVESTIGATE-otlp-headers-standard-compliance.md). No quoting gymnastics needed as a result, but still load .env with set -a && source .env && set +a rather than export $(grep ... | xargs), which mishandles values containing spaces regardless.

5. logs/ Directory

  • Output directory for file-based logs
  • Created automatically by the test if it doesn't exist
  • Contains dev.log (main) and error.log (errors only)

Why This Structure?

Enables automated verification:

# Generic tool works for ALL languages
./tools/validation/uis/run-company-lookup.sh python
./tools/validation/uis/run-company-lookup.sh typescript
./tools/validation/uis/run-company-lookup.sh go

# Tool internally does:
# cd /workspace/{language}/test/e2e/company-lookup && ./run-test.sh

Simplifies documentation:

  • Templates can reference test/e2e/company-lookup/run-test.sh for all languages
  • Verification instructions are language-agnostic
  • No need to document language-specific test commands

Ensures consistency:

  • All implementations run the same test suite
  • Verification process is identical across languages
  • LLMs can implement new languages following the convention

Reference Implementations

Python: /workspace/python/test/e2e/company-lookup/ TypeScript: /workspace/typescript/test/e2e/company-lookup/

Both serve as templates for implementing new languages.


Verification Tools

The tools/validation/uis/ directory provides language-agnostic verification tools that simplify testing and verification:

Quick Smoke Test

./tools/validation/uis/run-company-lookup.sh python
./tools/validation/uis/run-company-lookup.sh typescript
  • Runs application inside devcontainer
  • Sends telemetry to OTLP endpoints
  • Fast (seconds), no backend queries
  • Use during development

Complete E2E Test

LOG_FILE="python/test/e2e/company-lookup/logs/dev.log"
./tools/validation/uis/query-loki.sh sovdev-test-company-lookup-python --compare-with "$LOG_FILE"
./tools/validation/uis/query-tempo.sh sovdev-test-company-lookup-python --compare-with "$LOG_FILE"
./tools/validation/uis/query-prometheus.sh sovdev-test-company-lookup-python --compare-with "$LOG_FILE"
./tools/validation/uis/compare-with-master.sh python
  • Runs against a language's E2E test output
  • Exact-match comparison against the log file (trace_id/event_id), not just "found"
  • compare-with-master.sh confirms it's field-by-field identical to TypeScript's output
  • Use for official verification

Backend Query Tools

Query individual backends for debugging or verification:

Query Loki (Logs):

./tools/validation/uis/query-loki.sh sovdev-test-company-lookup-python
./tools/validation/uis/query-loki.sh sovdev-test-company-lookup-python --json --limit 20

Query Prometheus (Metrics):

./tools/validation/uis/query-prometheus.sh sovdev-test-company-lookup-python
./tools/validation/uis/query-prometheus.sh sovdev-test-company-lookup-python --json

Query Tempo (Traces):

./tools/validation/uis/query-tempo.sh sovdev-test-company-lookup-python
./tools/validation/uis/query-tempo.sh sovdev-test-company-lookup-python --json --limit 10

Benefits:

  • ✅ Works identically for all languages
  • ✅ Abstracts devcontainer vs host complexity
  • ✅ Dual output modes (human-readable + JSON)
  • ✅ Composable for custom workflows

See tools/validation/uis/README.md for complete documentation.


Test Categories

1. API Function Tests

Verify each of the 8 API functions works correctly.

2. Field Validation Tests

Verify all required fields are present in correct format.

3. Transport Tests

Verify output to all three destinations (OTLP, console, file).

4. Security Tests

Verify credential removal and stack trace limiting.

5. Integration Tests

Verify data flows through the complete stack (application → OTLP → Loki/Prometheus/Tempo → Grafana).


Test Scenario 1: Basic INFO Log

Purpose: Verify basic logging functionality with minimum required fields.

Test Code:

sovdev_log(
SOVDEV_LOGLEVELS.INFO,
'testFunction',
'Test message',
PEER_SERVICES.INTERNAL,
{ inputData: 'test' },
{ outputData: 'result' }
);
await sovdev_shutdown();

Expected OTLP Output (Loki):

{
"scope_name": "sovdev-test-app",
"scope_version": "1.0.0",
"severity_number": 9,
"severity_text": "INFO",
"service_name": "sovdev-test-app",
"service_version": "1.0.0",
"function_name": "testFunction",
"message": "Test message",
"peer_service": "sovdev-test-app",
"trace_id": "<uuid>",
"event_id": "<uuid>",
"session_id": "<uuid>",
"input_json": "{\"inputData\":\"test\"}",
"response_json": "{\"outputData\":\"result\"}",
"log_type": "transaction",
"observed_timestamp": "<nanoseconds>"
}

Expected Console Output:

YYYY-MM-DD HH:mm:ss [INFO] sovdev-test-app
Function: testFunction
Message: Test message
Trace ID: <uuid>
Session ID: <uuid>

Expected File Output:

{
"timestamp": "YYYY-MM-DDTHH:mm:ss.ffffff+00:00",
"level": "info",
"service_name": "sovdev-test-app",
"service_version": "1.0.0",
"function_name": "testFunction",
"message": "Test message",
"trace_id": "<uuid>",
"event_id": "<uuid>",
"session_id": "<uuid>",
"peer_service": "sovdev-test-app",
"input_json": "{\"inputData\":\"test\"}",
"response_json": "{\"outputData\":\"result\"}",
"log_type": "transaction"
}

Test Scenario 2: ERROR Log with Exception

Purpose: Verify error logging with exception processing and security cleanup.

Test Code:

try {
throw new Error('HTTP 404: Not Found');
} catch (error) {
sovdev_log(
SOVDEV_LOGLEVELS.ERROR,
'lookupCompany',
'Failed to lookup company 123456789',
PEER_SERVICES.BRREG,
{ orgNumber: '123456789' },
null,
error as Error,
traceId
);
}
await sovdev_shutdown();

Expected OTLP Output (Loki):

{
"scope_name": "sovdev-test-app",
"severity_number": 17,
"severity_text": "ERROR",
"function_name": "lookupCompany",
"message": "Failed to lookup company 123456789",
"peer_service": "SYS1234567",
"trace_id": "<uuid>",
"input_json": "{\"orgNumber\":\"123456789\"}",
"response_json": "null",
"exception_type": "Error",
"exception_message": "HTTP 404: Not Found",
"exception_stack": "<stack trace max 350 chars>"
}

Expected Console Output:

YYYY-MM-DD HH:mm:ss [ERROR] sovdev-test-app
Function: lookupCompany
Message: Failed to lookup company 123456789
Trace ID: <uuid>
Error: HTTP 404: Not Found
Stack: <stack trace>

Expected File Output:

{
"timestamp": "YYYY-MM-DDTHH:mm:ss.ffffff+00:00",
"level": "error",
"service_name": "sovdev-test-app",
"service_version": "1.0.0",
"function_name": "lookupCompany",
"message": "Failed to lookup company 123456789",
"exception_type": "Error",
"exception_message": "HTTP 404: Not Found",
"exception_stack": "<stack trace max 350 chars>",
"trace_id": "<uuid>",
"peer_service": "SYS1234567",
"input_json": "{\"orgNumber\":\"123456789\"}",
"response_json": "null",
"log_type": "transaction"
}

Security Requirements:

  • Stack trace MUST be truncated to 350 characters maximum
  • Stack trace MUST have credentials removed (auth headers, passwords, tokens)
  • Exception type MUST be "Error" (not language-specific like "Exception" or "TypeError")

Test Scenario 3: Job Status Log

Purpose: Verify batch job tracking with job status logging.

Test Code:

const batchTraceId = sovdev_generate_trace_id();

sovdev_log_job_status(
SOVDEV_LOGLEVELS.INFO,
'batchProcess',
'CompanyLookupBatch',
'Started',
PEER_SERVICES.INTERNAL,
{ totalItems: 100 },
batchTraceId
);

// Process items...

sovdev_log_job_status(
SOVDEV_LOGLEVELS.INFO,
'batchProcess',
'CompanyLookupBatch',
'Completed',
PEER_SERVICES.INTERNAL,
{ totalItems: 100, successCount: 98, errorCount: 2 },
batchTraceId
);

await sovdev_shutdown();

Expected OTLP Output (Loki) - Job Started:

{
"severity_number": 9,
"severity_text": "INFO",
"function_name": "batchProcess",
"message": "Job Started: CompanyLookupBatch",
"peer_service": "sovdev-test-app",
"trace_id": "<same-uuid-for-entire-batch>",
"input_json": "{\"jobName\":\"CompanyLookupBatch\",\"jobStatus\":\"Started\",\"totalItems\":100}",
"response_json": "null",
"log_type": "job.status"
}

Expected OTLP Output (Loki) - Job Completed:

{
"severity_number": 9,
"severity_text": "INFO",
"function_name": "batchProcess",
"message": "Job Completed: CompanyLookupBatch",
"peer_service": "sovdev-test-app",
"trace_id": "<same-uuid-as-started>",
"input_json": "{\"jobName\":\"CompanyLookupBatch\",\"jobStatus\":\"Completed\",\"totalItems\":100,\"successCount\":98,\"errorCount\":2}",
"response_json": "null",
"log_type": "job.status"
}

Requirements:

  • Both logs MUST have same trace_id
  • Message format MUST be "Job {status}: {jobName}"
  • log_type MUST be "job.status"
  • input_json MUST contain jobName, jobStatus, and metadata

Test Scenario 4: Job Progress Log

Purpose: Verify individual item progress tracking in batch jobs.

Test Code:

for (let i = 0; i < totalItems; i++) {
const itemId = items[i].id;

sovdev_log_job_progress(
SOVDEV_LOGLEVELS.INFO,
'processItem',
itemId,
i + 1,
totalItems,
PEER_SERVICES.BRREG,
{ orgNumber: itemId },
batchTraceId
);

// Process item...
}
await sovdev_shutdown();

Expected OTLP Output (Loki):

{
"severity_number": 9,
"severity_text": "INFO",
"function_name": "processItem",
"message": "Processing 971277882 (25/100)",
"peer_service": "SYS1234567",
"trace_id": "<batch-trace-id>",
"input_json": "{\"itemId\":\"971277882\",\"currentItem\":25,\"totalItems\":100,\"progressPercentage\":25,\"orgNumber\":\"971277882\"}",
"response_json": "null",
"log_type": "job.progress"
}

Requirements:

  • trace_id MUST match job status logs
  • Message format MUST be "Processing {itemId} ({current}/{total})"
  • input_json MUST contain: itemId, currentItem, totalItems, progressPercentage
  • progressPercentage MUST be Math.round((current / total) * 100)
  • log_type MUST be "job.progress"

Test Scenario 5: Null Response Handling

Purpose: Verify responseJSON field is always present even when null.

Test Code:

sovdev_log(
SOVDEV_LOGLEVELS.ERROR,
'lookupCompany',
'Company not found',
PEER_SERVICES.BRREG,
{ orgNumber: '999999999' },
null, // Explicitly no response
new Error('HTTP 404: Not Found')
);
await sovdev_shutdown();

Expected OTLP Output (Loki):

{
"function_name": "lookupCompany",
"message": "Company not found",
"input_json": "{\"orgNumber\":\"999999999\"}",
"response_json": "null",
"exception_type": "Error",
"exception_message": "HTTP 404: Not Found"
}

Critical Requirement:

  • response_json field MUST be present with value "null" (string, not JSON null)
  • Field presence must be consistent across all log types

Test Scenario 6: Credential Removal from Stack Traces

Purpose: Verify security cleanup removes credentials from exception stack traces.

Test Code:

try {
const response = await fetch('https://api.example.com/data', {
headers: {
'Authorization': 'Bearer secret-token-12345',
'X-API-Key': 'api-key-67890'
}
});
} catch (error) {
sovdev_log(
SOVDEV_LOGLEVELS.ERROR,
'apiCall',
'API call failed',
PEER_SERVICES.EXTERNAL_API,
null,
null,
error as Error
);
}
await sovdev_shutdown();

Expected OTLP Output (Loki):

{
"exception_type": "Error",
"exception_message": "API call failed",
"exception_stack": "<stack trace with credentials removed>"
}

Security Requirements:

  • Stack trace MUST NOT contain "secret-token-12345"
  • Stack trace MUST NOT contain "api-key-67890"
  • Common credential patterns MUST be removed:
    • Authorization headers (Bearer tokens, Basic auth)
    • API keys
    • Passwords
    • JWT tokens
    • Cookie values

Regex patterns to remove:

/Authorization[:\s]+[^\s,}]+/gi
/password[:\s=]+[^\s,}]+/gi
/api[-_]?key[:\s=]+[^\s,}]+/gi
/Bearer\s+[A-Za-z0-9\-._~+/]+=*/gi

Test Scenario 7: Trace Correlation Across Multiple Operations

Purpose: Verify traceId correlation links related operations.

Test Code:

const traceId = sovdev_generate_trace_id();

sovdev_log(
SOVDEV_LOGLEVELS.INFO,
'startTransaction',
'Starting transaction',
PEER_SERVICES.INTERNAL,
{ transactionId: 'TXN-001' },
null,
null,
traceId
);

sovdev_log(
SOVDEV_LOGLEVELS.INFO,
'callExternalAPI',
'Calling external API',
PEER_SERVICES.BRREG,
{ request: 'data' },
{ response: 'result' },
null,
traceId
);

sovdev_log(
SOVDEV_LOGLEVELS.INFO,
'completeTransaction',
'Transaction completed',
PEER_SERVICES.INTERNAL,
{ transactionId: 'TXN-001' },
{ status: 'success' },
null,
traceId
);

await sovdev_shutdown();

Expected Behavior:

  • All three logs MUST have identical trace_id
  • Grafana query {service_name="sovdev-test-app"} | json | trace_id="<uuid>" MUST return all three logs
  • Logs should be linkable in Grafana UI via trace_id

Test Scenario 8: Session Correlation

Purpose: Verify sessionId links all logs from a single execution.

Test Code:

// Single execution, multiple operations
sovdev_initialize('sovdev-test-app', '1.0.0');

sovdev_log(SOVDEV_LOGLEVELS.INFO, 'operation1', 'First operation', PEER_SERVICES.INTERNAL);
sovdev_log(SOVDEV_LOGLEVELS.INFO, 'operation2', 'Second operation', PEER_SERVICES.INTERNAL);
sovdev_log(SOVDEV_LOGLEVELS.INFO, 'operation3', 'Third operation', PEER_SERVICES.INTERNAL);

await sovdev_shutdown();

Expected Behavior:

  • All logs MUST have identical session_id
  • session_id MUST be generated once at initialization
  • session_id MUST be UUID v4 format (lowercase)
  • Grafana query {service_name="sovdev-test-app"} | json | session_id="<uuid>" MUST return all logs from this execution

Test Scenario 9: Metrics Generation

Purpose: Verify OpenTelemetry metrics are generated from log calls.

Test Code:

// Log several operations
sovdev_log(SOVDEV_LOGLEVELS.INFO, 'operation1', 'Op 1', PEER_SERVICES.INTERNAL);
sovdev_log(SOVDEV_LOGLEVELS.INFO, 'operation2', 'Op 2', PEER_SERVICES.BRREG);
sovdev_log(SOVDEV_LOGLEVELS.ERROR, 'operation3', 'Failed', PEER_SERVICES.BRREG, null, null, new Error('test'));
await sovdev_shutdown();

Expected Prometheus Metrics:

# Query: sovdev_operations_total
sovdev_operations_total{service_name="sovdev-test-app"} >= 3

# Query: sovdev_errors_total
sovdev_errors_total{service_name="sovdev-test-app",exception_type="Error"} >= 1

Verification Command:

# Human-readable output
./tools/validation/uis/query-prometheus.sh sovdev-test-app

# JSON output for automated verification
./tools/validation/uis/query-prometheus.sh sovdev-test-app --json | \
jq '.data.result[] | select(.metric.__name__ == "sovdev_operations_total")'

Test Scenario 10: Trace Generation

Purpose: Verify OpenTelemetry spans are created for log operations.

Test Code:

sovdev_log(SOVDEV_LOGLEVELS.INFO, 'testOperation', 'Test trace', PEER_SERVICES.BRREG);
await sovdev_shutdown();

Expected Tempo Traces:

  • Trace with service.name="sovdev-test-app" should exist
  • Span should have attributes matching log fields

Verification Command:

# Human-readable output
./tools/validation/uis/query-tempo.sh sovdev-test-app

# JSON output for automated verification
./tools/validation/uis/query-tempo.sh sovdev-test-app --json | \
jq '.traces[] | {trace_id, rootServiceName, rootTraceName}'

Test Scenario 11: Grafana Dashboard Verification

Purpose: Verify all logs appear in Grafana with correct fields.

Test Code:

// Run full E2E test with multiple log types
const batchTraceId = sovdev_generate_trace_id();

sovdev_log_job_status(SOVDEV_LOGLEVELS.INFO, 'batch', 'TestBatch', 'Started', PEER_SERVICES.INTERNAL, {}, batchTraceId);
sovdev_log(SOVDEV_LOGLEVELS.INFO, 'process', 'Processing', PEER_SERVICES.BRREG);
sovdev_log(SOVDEV_LOGLEVELS.ERROR, 'process', 'Failed', PEER_SERVICES.BRREG, null, null, new Error('Test error'));
sovdev_log_job_status(SOVDEV_LOGLEVELS.INFO, 'batch', 'TestBatch', 'Completed', PEER_SERVICES.INTERNAL, {}, batchTraceId);

await sovdev_shutdown();

Verification in Grafana:

  1. Open http://grafana.localhost
  2. Navigate to "Structured Logging Testing Dashboard"
  3. Filter: systemId =~ /^sovdev-test-.*/
  4. Verify tables show:
    • Transaction Logs: INFO and ERROR logs with all fields
    • Recent Errors: ERROR log with exception details
    • Job Status Tracking: Started and Completed logs
    • Active Sessions: Current session_id

Required Fields in Dashboard:

  • timestamp (human-readable)
  • service_name
  • function_name
  • message
  • peer_service
  • trace_id
  • log_type
  • exception_type (for errors)
  • exception_message (for errors)

Test Validation Checklist

✅ Automated Verification (Use These Tools First!)

IMPORTANT: These tools automatically verify all test scenarios. Use them instead of manual verification.

1. Validate log file format:

./tools/validation/uis/validate-log-format.sh {language}/test/e2e/company-lookup/logs/dev.log

This tool automatically checks:

  • All required fields present in correct format
  • JSON serialization correct
  • Field values (UUIDs, timestamps, severity)
  • Stack traces within limits
  • Flat snake_case structure

2. Quick smoke test:

./tools/validation/uis/run-company-lookup.sh {language}

This tool automatically:

  • Runs test application in devcontainer
  • Sends telemetry to OTLP endpoints
  • Validates basic functionality
  • Fast (5 seconds)

3. Complete E2E validation:

LOG_FILE="{language}/test/e2e/company-lookup/logs/dev.log"
./tools/validation/uis/query-loki.sh sovdev-test-company-lookup-{language} --compare-with "$LOG_FILE"
./tools/validation/uis/query-tempo.sh sovdev-test-company-lookup-{language} --compare-with "$LOG_FILE"
./tools/validation/uis/query-prometheus.sh sovdev-test-company-lookup-{language} --compare-with "$LOG_FILE"
./tools/validation/uis/compare-with-master.sh {language}

This verifies:

  • ✅ OTLP export to all backends
  • ✅ Logs arrived in Loki, exact match against the log file
  • ✅ Metrics in Prometheus (sovdev_operations_total, sovdev_errors_total), exact match
  • ✅ Traces in Tempo, exact match
  • ✅ Field-by-field identical to TypeScript's reference output

Result: If all four tools pass, your implementation is complete! ✅


📝 Manual Verification (Optional, for Deep Debugging)

Only use manual verification if automated tools fail and you need to debug specific issues.

OTLP Output (Loki) - Query manually:

./tools/validation/uis/query-loki.sh {service-name}
./tools/validation/uis/query-loki.sh {service-name} --json | jq

Verify:

  • All required fields present
  • Field values in correct format (UUIDs, timestamps, severity numbers)
  • JSON serialization correct (input_json, response_json)
  • Exception handling correct (type, message, stack)
  • Credentials removed from stack traces
  • Stack traces limited to 350 characters

Console Output - Check terminal:

  • Human-readable format
  • Color coding appropriate (red for ERROR, yellow for WARN, etc.)
  • Essential fields displayed (timestamp, level, service, function, message)
  • Exception details shown for errors

File Output - Inspect logs/ directory:

  • Valid JSON (one log per line)
  • All required fields present
  • Flat snake_case structure (service_name, function_name, etc.)
  • Compact format (no pretty-printing)

Metrics (Prometheus) - Query manually:

./tools/validation/uis/query-prometheus.sh {service-name}
./tools/validation/uis/query-prometheus.sh {service-name} --json | jq

Verify:

  • sovdev_operations_total increments
  • sovdev_errors_total increments for errors
  • Labels correct (service_name, exception_type)

Traces (Tempo) - Query manually:

./tools/validation/uis/query-tempo.sh {service-name}
./tools/validation/uis/query-tempo.sh {service-name} --json | jq

Verify:

  • Spans created for operations
  • Span attributes match log fields
  • service.name correct

Grafana Dashboard - Open in browser:

  1. Navigate to http://grafana.localhost
  2. Open "Structured Logging Testing Dashboard"
  3. Filter: systemId =~ /^sovdev-test-.*/

Verify:

  • Logs appear in all relevant panels
  • Fields displayed correctly
  • Filtering works (by service, trace_id, session_id)
  • Error logs highlighted
  • Job tracking shows progress

Performance Requirements

Latency

  • Target: < 1ms per log call (excluding network I/O)
  • Measurement: Log 1000 operations, measure total time
  • Test: for i in range(1000): sovdevLog(...)

Memory Usage

  • Target: < 10MB additional memory for logger initialization
  • Target: < 1KB per log entry before batching
  • Measurement: Monitor process memory before/after initialization

Throughput

  • Target: Support 1000+ logs/second without blocking
  • Test: Generate high-volume logs, verify no application slowdown

Batch Flushing

  • Target: Flush completes within 30 seconds
  • Test: Log 100 entries, call sovdevFlush(), measure time

Error Handling Tests

Test: Missing Required Fields

// Should throw/return error
sovdev_log(
null, // Invalid: null level
'function',
'message',
PEER_SERVICES.INTERNAL
);

Expected: Error or warning logged, operation continues

Test: OpenTelemetry Export Failure

// Configure invalid OTLP endpoint
process.env.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT = 'http://invalid-host/logs';

sovdev_log(SOVDEV_LOGLEVELS.INFO, 'test', 'Test message', PEER_SERVICES.INTERNAL);
await sovdev_shutdown();

Expected:

  • Console log shows warning about export failure
  • Application continues without crashing
  • Console and file outputs still work

Language-Specific Test Adaptations

TypeScript/JavaScript

  • Use Error class for exceptions
  • Use async/await for sovdevShutdown()
  • Use process.env for environment variables

Python

  • Use Exception class (converted to "Error" in output)
  • Use sovdev_shutdown() (synchronous — no await, unlike TypeScript)
  • Use os.environ for environment variables

Go (Future)

  • Use error type (converted to "Error" in output)
  • Use goroutines for async operations
  • Use os.Getenv() for environment variables

Success Criteria

An implementation passes all tests when:

  1. ✅ All 11 test scenarios produce correct output in OTLP/console/file
  2. ✅ All required fields present with correct types
  3. ✅ Security features work (credential removal, stack limiting)
  4. ✅ Metrics appear in Prometheus
  5. ✅ Traces appear in Tempo
  6. ✅ Logs visible in Grafana with all fields
  7. ✅ Performance requirements met
  8. ✅ Error handling graceful (no crashes)

Document Status: ✅ v1.0.0 COMPLETE Last Updated: 2025-10-27 Part of: sovdev-logger specification v1.1.0