Skip to content

feat(telemetry): replace RavenDB ingestion with ClickHouse + dual OTLP export - #5

Open
sharpoverride wants to merge 44 commits into
mainfrom
feat/clickhouse-telemetry
Open

sharpoverride wants to merge 44 commits into
mainfrom
feat/clickhouse-telemetry

Conversation

@sharpoverride

Copy link
Copy Markdown
Owner

Summary

This PR removes the custom RavenDB ingestion service and replaces it with a local ClickHouse container fed directly by the OpenTelemetry Collector. Telemetry is still visible in the Aspire Dashboard via a direct OTLP exporter on each service.

What changed

  • Removed the MedicineTrack.RavenDB.Ingestion project and all solution/AppHost references.
  • Added a local ClickHouse container to the Aspire AppHost:
    • HTTP endpoint on 8123 used by the collector exporter.
    • Native TCP endpoint on 9000.
    • HTTP health check on /ping so WaitFor(clickHouse) waits for the right port.
  • Added clickhouse-init/ schema initialization and clickhouse-config/ bind mounts for default user + network settings.
  • Updated otel-collector-config.yaml:
    • Removed the otlp/aspire dashboard exporter (Aspire OTLP requires TLS/auth; direct fan-out returned 403).
    • Added clickhouse exporter pointing to http://clickhouse:8123.
  • Each .NET project now has dual OTLP export:
    • WithOtlpExporter() in AppHost sends traces/logs/metrics directly to the Aspire Dashboard.
    • A second programmatic AddOtlpExporter() sends gRPC OTLP to the collector, which writes to ClickHouse.
  • Replaced RavenDB validation scripts with:
    • scripts/validate-clickhouse-ingestion.sh
    • scripts/clickhouse-test-queries.sql
  • Updated README.md telemetry section for ClickHouse + Aspire Dashboard.
  • Removed stale RavenDB entries from .idea/workspace.xml.

Verification

  • Solution builds: dotnet build src/MedicineTrack.sln
  • E2E tests: 48/48 passed
  • Unit tests: 18/18 passed
  • ClickHouse validation script reports receiving traces, logs, and metric sum points.

Breaking changes

  • RavenDB telemetry ingestion is removed entirely; any downstream consumers of the RavenDB documents will need to query ClickHouse or the Aspire Dashboard instead.

Created by OpenCode.

Mihai Lazăr and others added 30 commits January 14, 2026 06:26
- Add Kusto emulator Docker container (mcr.microsoft.com/azuredataexplorer/kustainer-linux:latest)
- Configure port 8080 for HTTP endpoint
- Set 4GB memory limit
- Add bind mount for ./kusto-data persistence
- Set ACCEPT_EULA=Y environment variable

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Create MedicineTrack.Kusto.Init console project
- Add Microsoft.Azure.Kusto.Data NuGet package (12.2.2)
- Create init-kusto-schema.kql with Application Insights schema tables
- Add project to solution file
- Create stub Program.cs (full implementation in KUSTO-1.3)

Tables defined:
- traces: application logs with severity levels
- requests: HTTP requests with duration and result codes
- dependencies: external calls (DB, HTTP) with timing
- exceptions: error details with stack traces

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Implement full KustoSchemaInitializer with retry logic
- Connect to Kusto emulator with 10 retries (5 second intervals)
- Read and execute init-kusto-schema.kql commands
- Handle already-exists errors gracefully
- Parse and execute multi-command KQL scripts
- Add comprehensive error handling and logging
- Support Kusto__ConnectionString environment variable

Features:
- 10 retries with 5s delay for emulator startup wait
- Command-by-command execution with error handling
- Idempotent: skips existing databases/tables
- Clear console output for debugging

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add otel-collector-config.yaml at solution root
- Configure OTLP gRPC receiver on port 4317
- Configure OTLP HTTP receiver on port 4318
- Add batch processor (10s timeout, 100 batch size)
- Add attributes processor for Application Insights schema mapping
- Add resource processor for itemType attribute
- Configure file exporter for MVP (JSON format, 50MB rotation)
- Add logging exporter for debugging (info level)

Pipelines:
- traces: OTLP → batch → attributes → file/logging
- logs: OTLP → batch → attributes → resource → file/logging

File exporter will be replaced with HTTP to Kusto ingestion service in Phase 3.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add OpenTelemetry Collector contrib container
- Expose port 4318 for OTLP HTTP endpoint
- Expose port 4317 for OTLP gRPC endpoint
- Mount otel-collector-config.yaml from solution root
- Mount ./otel-data for file output persistence
- Set WaitFor dependency on Kusto emulator

Services can now send telemetry to otel-collector:4318 (HTTP) or
otel-collector:4317 (gRPC) and it will be processed and exported.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Create MedicineTrack.Kusto.Ingestion ASP.NET Core minimal API project
- Add Microsoft.Azure.Kusto.Data and Ingest packages (12.2.2)
- Add OpenTelemetry packages for instrumentation
- Create Models/, Mappers/, Services/ directory structure
- Add project to solution file
- Add project reference to AppHost
- Register kustoIngestion service in AppHost with port 5003
- Configure Kusto__ConnectionString environment variable

Stub Program.cs includes:
- OpenTelemetry logging and tracing
- Health check endpoint at /health
- Placeholders for service registration and endpoints (KUSTO-3.4, 3.5)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Create record types matching Application Insights schema for Kusto ingestion:

- TraceData: Application logs with severity levels, operation context
- RequestData: HTTP requests with duration, result codes, measurements
- DependencyData: External calls (DB, HTTP) with timing and success status
- ExceptionData: Error details with stack traces and exception hierarchy

All models include:
- Timestamp (DateTimeOffset)
- Operation context (OperationName, OperationId)
- Cloud role identification (CloudRoleName, CloudRoleInstance)
- Custom dimensions for additional metadata
- ItemType for Application Insights compatibility

Models use record types for immutability following codebase patterns.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Create ApplicationInsightsMapper for converting OTEL Collector JSON exports
to Application Insights schema:

Mappers implemented:
- MapLogRecordFromJson: OTLP logs → TraceData
  * Severity mapping (OTLP 0-24 → AppInsights 0-4)
  * Extract trace context, message, attributes
- MapSpanToRequest: Server spans → RequestData
  * HTTP requests with URL, status code, duration
  * Operation correlation via trace ID
- MapSpanToDependency: Client/Internal spans → DependencyData
  * Detect type (SQL, HTTP, RPC, Queue)
  * Extract target, data, status
  * Duration tracking

Helper methods:
- ExtractAttributes: Parse OTLP attribute arrays
- ExtractResourceAttributes: Extract service metadata
- DetermineDependencyType: Classify dependency by attributes
- DetermineSuccess: Map status codes to success boolean

Handles OTEL Collector file exporter JSON format with graceful error handling.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Create KustoIngestionService for ingesting telemetry into Kusto emulator:

Interface: IKustoIngestionService
- IngestTracesAsync: Insert logs into traces table
- IngestRequestsAsync: Insert HTTP requests into requests table
- IngestDependenciesAsync: Insert external calls into dependencies table
- IngestExceptionsAsync: Insert errors into exceptions table

Implementation features:
- Uses Kusto .ingest inline commands for emulator compatibility
- CSV format generation with proper escaping
- JSON serialization for dynamic columns (customDimensions)
- Batch processing support
- Comprehensive error handling and structured logging
- Configurable connection string via Kusto__ConnectionString
- IDisposable for proper client cleanup

CSV escaping:
- Double-quotes escaped as ""
- All string fields wrapped in quotes
- Empty/null values as ""
- Dynamic columns serialized as JSON

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Implement minimal API endpoints for receiving telemetry data:

Endpoints added:
- POST /ingest/traces: Receive trace/log data
- POST /ingest/requests: Receive HTTP request data
- POST /ingest/dependencies: Receive dependency (external call) data
- POST /ingest/exceptions: Receive exception data
- GET /health: Health check endpoint

Features:
- Array-based input for batch processing
- Structured logging for all operations
- Error handling with ProblemDetails responses
- OpenAPI metadata (WithName, WithTags, Produces)
- Cancellation token support
- Success response with ingestion counts

Service registration:
- KustoIngestionService registered as singleton
- Automatic DI injection into endpoints

Following codebase patterns:
- Minimal APIs (no controllers)
- Structured logging with ILogger
- ProblemDetails for errors
- OpenTelemetry instrumentation

Phase 3 (Kusto Ingestion Bridge) complete!

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add gitignore patterns for runtime data directories:
- kusto-data/: Kusto emulator persistent data
- otel-data/: OpenTelemetry Collector file exports
- telemetry.json*: OTEL Collector JSON output files

Prevents committing:
- Kusto database files
- Telemetry export files
- Rotated log files

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add kusto-test-queries.kql with 22 queries organized by category:

Health Checks:
- Recent traces for service availability
- Table row counts to verify ingestion

Service Monitoring:
- Request volume by service
- Error rate calculation
- Service health overview with percentiles

Performance Analysis:
- Slow requests and dependencies
- Operation latency percentiles (P50, P95, P99)

Dependency Analysis:
- Dependencies by type and target
- Database query performance
- HTTP call analysis

Error Analysis:
- Exception summary and trends
- Recent exceptions with details
- Failed requests with context

Distributed Tracing:
- Trace requests across services
- Find distributed traces
- Service interaction mapping

Log Analysis:
- Log severity distribution
- Errors and warnings
- Keyword search

Aggregated Insights:
- Service interaction map
- Request timeline with 5-minute buckets
- Overall system health dashboard

All queries parameterized for easy testing and monitoring.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add validate-kusto-ingestion.sh bash script to automate testing:

Test Steps:
1. Test Kusto connection and database existence
2. Verify all tables exist (traces, requests, dependencies, exceptions)
3. Generate test traffic by calling service health endpoints
4. Wait for ingestion (10 seconds)
5. Validate data in all tables
6. Check schema compliance
7. Test distributed tracing correlation

Features:
- Color-coded output (green/red/yellow)
- Pass/fail tracking with counts
- Configurable URLs via environment variables
- KQL query execution via REST API
- Health check validation
- Schema compliance verification
- Trace correlation testing

Environment variables supported:
- KUSTO_URL (default: http://localhost:8080)
- GATEWAY_URL (default: http://localhost:5000)
- API_URL (default: http://localhost:5001)
- CONFIG_URL (default: http://localhost:5002)

Exit codes:
- 0: All checks passed
- 1: One or more checks failed

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Renamed project directory and .csproj file
- Updated all namespace references throughout project
- Updated solution file references
- Updated AppHost project references
- Changed service name in health check endpoint
- Updated log messages to reflect RavenDB

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Removed Microsoft.Azure.Kusto.Data package
- Removed Microsoft.Azure.Kusto.Ingest package
- Added RavenDB.Client version 6.2.3
- Stubbed out KustoIngestionService implementation (temporary)
- Service will be fully replaced with RavenDB in RAVEN-3.3

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Deleted src/MedicineTrack.Kusto.Init/ directory
- Removed project from solution file
- Removed all build configuration entries for Kusto.Init
- Kusto schema initialization not needed for RavenDB

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Added TraceDocument.cs with all required properties
- Id property follows RavenDB conventions (auto-generated)
- Timestamp as DateTime for RavenDB compatibility
- SeverityLevel as int (0-4 severity scale)
- CustomDimensions as Dictionary<string, string>
- Record type for immutability
- Added SpanId and ParentSpanId for trace hierarchy

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…ionDocument models

RAVEN-2.2: RequestDocument
- Success as bool (not string)
- DurationMs as double for precise timing
- CustomDimensions and CustomMeasurements as dictionaries
- Record type for immutability

RAVEN-2.3: DependencyDocument
- Type field for dependency type (SQL, HTTP, etc.)
- Target field for server/endpoint
- Data field for query/command
- Success as bool

RAVEN-2.4: ExceptionDocument
- Type, Message, Stack properties
- OuterType, OuterMessage for wrapped exceptions
- InnermostType, InnermostMessage for root cause
- Record type for immutability

All models follow RavenDB conventions with Id property and DateTime timestamps

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Added RavenDB DocumentStore configuration in Program.cs:
- Connection to https://ravendb.ravendb.orb.local
- Database name 'telemetry'
- Configuration via appsettings or environment variables
- Registered as singleton in DI container
- Proper initialization with error handling and logging

RAVEN-3.1 complete

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…uments

Updated mapper to create RavenDB document models:
- MapLogRecordFromJson now returns TraceDocument instead of TraceData
- MapSpanToRequest now returns RequestDocument instead of RequestData
- MapSpanToDependency now returns DependencyDocument instead of DependencyData
- Changed DateTimeOffset to DateTime using .UtcDateTime
- Changed Success from string to bool
- Changed Dictionary<string, object?> to Dictionary<string, string>
- Added SpanId extraction for correlation
- Renamed Duration to DurationMs
- Added ConvertToStringDictionary helper method
- Renamed DetermineSuccess to DetermineSuccessBool returning bool

RAVEN-3.2 complete

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Created new RavenDB ingestion service:
- IRavenDBIngestionService interface with Document type methods
- RavenDBIngestionService implementation using IDocumentStore
- IngestTracesAsync uses session.StoreAsync for TraceDocuments
- IngestRequestsAsync uses session.StoreAsync for RequestDocuments
- IngestDependenciesAsync uses session.StoreAsync for DependencyDocuments
- IngestExceptionsAsync uses session.StoreAsync for ExceptionDocuments
- Batch operations with SaveChangesAsync for efficiency
- Error handling with structured logging
- Registered in DI container as singleton

Old Kusto service kept temporarily for RAVEN-3.4 endpoint migration.

RAVEN-3.3 complete

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Updated all ingestion endpoints:
- POST /ingest/traces: TraceData → TraceDocument, uses IRavenDBIngestionService
- POST /ingest/requests: RequestData → RequestDocument
- POST /ingest/dependencies: DependencyData → DependencyDocument
- POST /ingest/exceptions: ExceptionData → ExceptionDocument
- Changed response field from "table" to "collection" (RavenDB terminology)
- All endpoints use IRavenDBIngestionService with ProblemDetails error handling
- Structured logging preserved

Removed old Kusto service files:
- Deleted IKustoIngestionService.cs
- Deleted KustoIngestionService.cs
- Deleted TraceData.cs, RequestData.cs, DependencyData.cs, ExceptionData.cs
- Removed Kusto service DI registration

RAVEN-3.4 complete - Phase 3 complete!

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Removed Kusto emulator configuration:
- Deleted Kusto container definition and all configuration
- Removed kusto-data volume mount reference
- Removed WaitFor(kusto) dependency from otelCollector
- Removed Kusto environment variable from ravendb-ingestion
- Removed WaitFor(kusto) dependency from ravendb-ingestion
- Updated comments to reflect RavenDB ingestion service

RavenDB ingestion service now standalone, no longer dependent on Kusto.

RAVEN-4.1 complete

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Added RavenDB connection configuration:
- RavenDB URL configured via environment variable (default: https://ravendb.ravendb.orb.local)
- RavenDB database name configured (default: telemetry)
- Configuration can be overridden via appsettings.json with RavenDB:Url and RavenDB:Database
- Environment variables passed to ravendb-ingestion service using double underscore notation
- RavenDB ingestion service receives configuration automatically from AppHost

RAVEN-4.2 complete

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Updated OpenTelemetry Collector configuration:
- Updated comment to reference RavenDB instead of Kusto
- File exporter still configured (works for both file-based and future HTTP export)
- Batch processor settings remain appropriate (10s timeout, 100/200 batch sizes)
- Collector can start without Kusto dependency
- Configuration file remains valid YAML
- Future enhancement path documented for HTTP export to RavenDB ingestion endpoint

RAVEN-4.3 complete - Phase 4 complete!

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Created three custom indexes for efficient querying:
- Traces_ByServiceAndTime: Query traces by service, timestamp, severity
- Requests_ByServiceAndStatus: Query requests by service, success status, duration
- Telemetry_ByTraceId: Multi-map index for distributed tracing correlation

Indexes are automatically deployed on service startup using IndexCreation.CreateIndexes().
Enables efficient queries for:
- Service health monitoring (traces by time range)
- Error rate analysis (requests by status)
- Distributed trace correlation (all telemetry by OperationId)

RAVEN-5.1 complete

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Created comprehensive RQL query examples for telemetry analysis:
1. Recent traces (service health check)
2. Request volume by service (performance monitoring)
3. Slow dependencies (bottleneck identification)
4. Exceptions by service (error analysis)
5. Distributed trace correlation (cross-service debugging)
6. Error rate by service (SLA monitoring)
7. High severity traces (critical issue monitoring)
8. Request duration percentiles (latency analysis)
9. Service-to-service call map (dependency mapping)
10. Failed requests with details (error investigation)

Deleted old Kusto queries file (kusto-test-queries.kql).
All queries documented with descriptions and use cases.

RAVEN-5.2 complete - Phase 5 complete!

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…sting

- Created scripts/validate-ravendb-ingestion.sh with 7 validation steps
- Tests RavenDB connection and database access
- Verifies collection existence (Traces, Requests, Dependencies, Exceptions)
- Generates test traffic to services
- Validates data ingestion via RQL queries
- Checks schema compliance for document fields
- Tests distributed tracing correlation using OperationId
- Tests custom index availability
- Returns clear pass/fail status with colored output
- Made script executable (chmod +x)
- Added deprecation notice to validate-kusto-ingestion.sh

Story: RAVEN-6.1 - Create RavenDB validation script

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…umentation

- Updated architecture diagram to include Telemetry & Observability layer
- Added RavenDB Ingestion Service to services overview
- Updated project structure to include RavenDB.Ingestion and scripts
- Added comprehensive "Telemetry with RavenDB" section with:
  - Architecture flow diagram (Services → OTEL → Ingestion → RavenDB)
  - RavenDB setup instructions and configuration examples
  - Documentation for all 4 telemetry collections (Traces, Requests, Dependencies, Exceptions)
  - RQL query examples for each collection
  - Distributed tracing examples using OperationId
  - Custom indexes documentation
  - Validation script usage instructions
  - Troubleshooting guide for common issues
- Added RavenDB Ingestion and Studio URLs to Quick Start
- Added RavenDB Ingestion health check endpoint
- Removed all Kusto references

Story: RAVEN-7.1 - Update project documentation for RavenDB

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Commented out kusto-data/ entries with deprecation note
- Added note: "deprecated - migrated to RavenDB"
- Kept OpenTelemetry Collector output files ignored (still needed)
- No RavenDB credentials to ignore (external instance)

Story: RAVEN-7.2 - Update .gitignore entries

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Mihai Lazăr and others added 14 commits January 14, 2026 12:23
- Changed relative paths from ../ to ../../ in AppHost
- Created otel-data directory for collector output
- Fixed container mount error

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Changed 'logging' exporter to 'debug' (deprecated in latest OTEL Collector)
- Updated verbosity from loglevel to verbosity: normal
- Updated pipeline exporters from 'logging' to 'debug'

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…access

- Changed RavenDB URL from ravendb.ravendb.orb.local to 192.168.138.8
- Added ServicePointManager certificate validation callback to accept self-signed certs
- Fixes 'No route to host' error from Docker containers
- Required because .orb.local domains not accessible from container network

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Reverted from IP back to ravendb.ravendb.orb.local domain
- Kept ServicePointManager SSL validation bypass
- Service runs on host (not Docker) so can access .orb.local domains

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Changed RavenDB URL to http://localhost:8081 (working endpoint)
- Avoids TLS certificate validation issues with Tailscale HTTPS wrapper
- RavenDB container maps port 8080 -> host 8081

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…tion

Add standard OTLP v1 endpoints (/v1/traces, /v1/logs) to RavenDB Ingestion Service
to receive telemetry directly from the OpenTelemetry Collector.

- Create OTLP request models (OtlpTraceRequest, OtlpLogsRequest)
- Implement OtlpMapper to convert OTLP format to RavenDB document models
- Add /v1/traces endpoint to receive spans and convert to TraceDocuments/RequestDocuments
- Add /v1/logs endpoint to receive logs and convert to TraceDocuments
- Update OTEL Collector config to export to new OTLP endpoints via otlphttp/ravendb
- Map OTLP span kinds (SERVER=2) to requests, others to traces
- Map OTLP severity levels to Application Insights severity scale
- Extract service.name as CloudRoleName for distributed tracing

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…ctor

Override OTEL_EXPORTER_OTLP_ENDPOINT for API, Config, and Gateway services
to send telemetry to the custom OTEL Collector on http://localhost:4318
instead of the Aspire Dashboard.

This enables the full telemetry pipeline:
Services → OTEL Collector → RavenDB Ingestion → RavenDB

The OTEL Collector will forward telemetry to RavenDB while also
maintaining file export and debug output.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Services use OTEL_EXPORTER_OTLP_PROTOCOL=grpc by default, so they need
to connect to the gRPC endpoint on port 4317, not the HTTP endpoint on 4318.

This fixes telemetry not flowing from services to the OTEL Collector.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…zation

- Configure JsonOptions with PropertyNameCaseInsensitive and camelCase policy
- Add explicit error handling for JSON deserialization in OTLP endpoints
- Return detailed error messages when deserialization fails
- Log warnings and errors with stack traces for debugging

This will help identify why OTEL Collector is receiving HTTP 400 errors
when attempting to export telemetry to the RavenDB Ingestion Service.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The OTEL Collector compresses JSON payloads with gzip by default,
causing deserialization to fail with '0x1F is an invalid start of value'
(0x1F 0x8B is the gzip magic number).

Added gzip decompression for both /v1/traces and /v1/logs endpoints:
- Check Content-Encoding header for gzip
- Wrap request body in GZipStream if compressed
- Deserialize from decompressed stream

This fixes HTTP 400 errors and allows telemetry to flow from
OTEL Collector → RavenDB Ingestion Service → RavenDB.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Removed obsolete ServicePointManager.ServerCertificateValidationCallback
since we're using HTTP localhost:8081 which doesn't require SSL certificate
validation bypass.

Also removed unused System.Net and System.Net.Security using statements.

Fixes SYSLIB0014 warning about obsolete WebRequest APIs.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…header

OTEL Collector doesn't set Content-Encoding header when compressing payloads.
Changed to detect gzip compression by reading the first two bytes (0x1F 0x8B)
which is the gzip magic number.

- Read request body into MemoryStream
- Check first 2 bytes for gzip signature
- Wrap in GZipStream if compressed
- Reset stream position before deserialization

This should now properly handle compressed OTLP payloads from the collector.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
… numbers

OTLP JSON sends numeric values as strings (e.g., "123" instead of 123) in
attribute values. System.Text.Json fails to deserialize these.

Created AnyValueJsonConverter that:
- Detects value type (string, number, boolean)
- Parses string representations of numbers/booleans
- Handles both numeric and string JSON representations

Applied converter to AnyValue record with JsonConverter attribute.

This fixes: "Cannot get the value of a token type 'String' as a number"

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…P export

- Remove MedicineTrack.RavenDB.Ingestion project and all references
- Add local ClickHouse container via Aspire AppHost with HTTP health check
- Add clickhouse-init schema and clickhouse-config user/network overrides
- Update OTEL Collector to write traces/logs/metrics directly to ClickHouse
- Each .NET service now exports to both Aspire dashboard (WithOtlpExporter)
  and the collector (second programmatic OTLP exporter using gRPC)
- Replace RavenDB validation scripts with ClickHouse validation script
  and sample ClickHouse SQL queries
- Update README telemetry section for ClickHouse and Aspire Dashboard
- Clean stale RavenDB entries from .idea/workspace.xml
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant