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
.envconfiguration (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/logsOTEL_EXPORTER_OTLP_METRICS_ENDPOINT=http://127.0.0.1/v1/metricsOTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://127.0.0.1/v1/tracesOTEL_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) anderror.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.shfor 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.shconfirms 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:
- Open
http://grafana.localhost - Navigate to "Structured Logging Testing Dashboard"
- Filter:
systemId =~ /^sovdev-test-.*/ - 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:
- Navigate to
http://grafana.localhost - Open "Structured Logging Testing Dashboard"
- 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
Errorclass for exceptions - Use
async/awaitforsovdevShutdown() - Use
process.envfor environment variables
Python
- Use
Exceptionclass (converted to "Error" in output) - Use
sovdev_shutdown()(synchronous — noawait, unlike TypeScript) - Use
os.environfor environment variables
Go (Future)
- Use
errortype (converted to "Error" in output) - Use goroutines for async operations
- Use
os.Getenv()for environment variables
Success Criteria
An implementation passes all tests when:
- ✅ All 11 test scenarios produce correct output in OTLP/console/file
- ✅ All required fields present with correct types
- ✅ Security features work (credential removal, stack limiting)
- ✅ Metrics appear in Prometheus
- ✅ Traces appear in Tempo
- ✅ Logs visible in Grafana with all fields
- ✅ Performance requirements met
- ✅ Error handling graceful (no crashes)
Document Status: ✅ v1.0.0 COMPLETE Last Updated: 2025-10-27 Part of: sovdev-logger specification v1.1.0