The LogRecord-specific properties that can be queried are listed below.

LogQueryRequest

message LogQueryRequest {
  repeated Where filters = 1;
  odddotnet.proto.common.v1.Take take = 2;
  optional odddotnet.proto.common.v1.Duration duration = 3;
}

Where

message Where {
  oneof value {
    PropertyFilter property = 1;
    OrFilter or = 2;
    odddotnet.proto.common.v1.InstrumentationScopeFilter instrumentation_scope = 3;
    odddotnet.proto.resource.v1.ResourceFilter resource = 4;
    odddotnet.proto.common.v1.StringProperty instrumentation_scope_schema_url = 5;
    odddotnet.proto.common.v1.StringProperty resource_schema_url = 6;
  }
}

PropertyFilter

message PropertyFilter {
  reserved 4;
  oneof value {
    odddotnet.proto.common.v1.UInt64Property time_unix_nano = 1;
    odddotnet.proto.common.v1.UInt64Property observed_time_unix_nano = 11;
    SeverityNumberProperty severity_number = 2;
    odddotnet.proto.common.v1.StringProperty severity_text = 3;
    odddotnet.proto.common.v1.AnyValueProperty body = 5;
    odddotnet.proto.common.v1.KeyValueListProperty attributes = 6;
    odddotnet.proto.common.v1.UInt32Property dropped_attributes_count = 7;
    odddotnet.proto.common.v1.UInt32Property flags = 8;
    odddotnet.proto.common.v1.ByteStringProperty trace_id = 9;
    odddotnet.proto.common.v1.ByteStringProperty span_id = 10;
  }
}

SeverityNumberProperty

message SeverityNumberProperty {
  odddotnet.proto.common.v1.EnumCompareAsType compare_as = 1;
  opentelemetry.proto.logs.v1.SeverityNumber compare = 2;
}

An Example

The following code, written in C#, shows how to manually build a request and send it to the test harness.

This example assumes you have the OddDotNet test harness spun up and ready to accept telemetry data. For ideas around how to do this, see the Quick Starts.

// ARRANGE
// Look for any logs associated with a specific TraceId
byte[] traceId = ...; // Some TraceId
var traceIdFilter = new PropertyFilter
{
  TraceId = new ByteStringProperty
  {
    CompareAs = ByteStringCompareAsType.Equals,
    Compare = traceId
  }
};

// Create the request
var request = new LogQueryRequest
{
  Take = new Take
  {
    TakeAll = new TakeAll()
  },
  Duration = new Duration
  {
    Milliseconds = 1000 // Wait up to 1 second to allow logs to flow in
  },
  Filters = { traceIdFilter } // Add our filter
};

// ACT
await TriggerWorkflowThatGeneratesLogs();

// ASSERT
var channel = GrpcChannel.ForAddress("http://localhost:4317");
var client = new LogQueryService.LogQueryServiceClient(channel);

LogQueryResponse response = await client.QueryAsync(request);

// Make some assertions on the logs returned
Assert.NotEmpty(response.Logs);

LogQueryRequestBuilder

The above code snippet is rather verbose. Because the LogQueryRequest is defined as a message in protobuf, we’re limited in the convenience methods available. The LogQueryRequestBuilder can simplify the process of building queries.

CSharp

The OddDotNet.Client NuGet package can be added to your project to leverage the pre-built gRPC client and the LogQueryRequestBuilder.

The builder can streamline the generation of requests to the LogQueryService. the above snippet of code in An Example can be simplified using the builder.

// ARRANGE
var request = new LogQueryRequestBuilder()
  .TakeAll() // Take all logs within the timeframe
  .Wait(TimeSpan.FromSeconds(1)) // Wait up to 1 second to allow logs to flow in
  .Where(filters => 
  {
    filters.AddTraceIdFilter(traceId, ByteStringCompareAsType.Equals); // Add our TraceId filter
  })
  .Build();

// ACT
await TriggerWorkflowThatGeneratesLogs();

// ASSERT
var channel = GrpcChannel.ForAddress("http://localhost:4317");
var client = new LogQueryService.LogQueryServiceClient(channel);

LogQueryResponse response = await client.QueryAsync(request);

// Make some assertions on the logs returned
Assert.NotEmpty(response.Logs);

Java

Not yet built. On the roadmap.

Go

Not yet built. On the roadmap.

Other languages

Support for other languages is not currently on the roadmap, but it is desired. Check back often to see the progress on your favorite language, or create a Discussion to advocate for the next supported language.

Remember, this is just for the Builder. Any language that supports gRPC and protobuf (and eventually HTTP and JSON) can use the test harness, it just won’t have the convenience of the Builder, so queries will need to be constructed manually, as outlined in An Example above.