Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the simplest example for trace API #13

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

Drumato
Copy link
Collaborator

@Drumato Drumato commented Jan 25, 2025

This PR achieves

  • Run the simplest example for trace API
    • create a TracerProvider with Syncer(that syncronously sends spans via SpanExporter)
    • create a trace that has a span
    • use StdoutExporter as a SpanExporter instance
    • to generate trace id, use random ID generator

Roadmap

How to implement generic interface

I think the std.mem.Allocator 's style is the best practice.
because the Zig users already know how to use it and implement it.

all interfaces in this PR follows the style.

@Drumato Drumato force-pushed the trace-smallest-example branch from 6a6c587 to 0da665b Compare January 26, 2025 01:40
Copy link
Collaborator

@inge4pres inge4pres left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting work @Drumato thanks for laying it out.
I left some questions below 🙏🏼

Comment on lines 18 to 62
pub fn isValid(self: Self) bool {
return Self.isValidValue(self.value);
}

pub fn isValidValue(value: [16]u8) bool {
for (value) |item| {
if (item != 0) {
return true;
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: why do we need two functions?
If it's part of the OTel specification, can you add a comment referencing the specification link that mandates having them?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isValidValue() is just needed because the check function i need before transforming the raw array to a trace id.
so I will remove it, thanks!

Comment on lines 44 to 91
pub fn isValid(self: Self) bool {
return Self.isValidValue(self.value);
}

pub fn isValidValue(value: [8]u8) bool {
for (value) |item| {
if (item != 0) {
return true;
}
}

return false;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same Q as for TraceID

Comment on lines 23 to 61
for (value) |item| {
if (item != 0) {
return true;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do I understand correctly that the only invalid value is an array of 16 u8s with all elemets set to 0?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes.
the specification about it is defined in https://opentelemetry.io/docs/specs/otel/trace/api/#isvalid.

/// but it is not defined in the OpenTelemetry specification, so for now we don't use it.
exportSpansFn: *const fn (
ctx: *anyopaque,
spans: []pb.Span,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I made a mistake in the metrics, see my reasoning in #11.
I am not sure coupling to the protobuf data structures here is a goo idea either.

Ideally, we would have an internal representation of Spans, and then only convert to protobuf in the otlp exporter, which is self-contained.
Making protobuf tyoes part of the interface method here will force us to couple the entire SDK to them, which is not desirable.

WDYT?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I strongly agree.
I will define another representation of Span.

};
}

pub fn exportSpans(ctx: *anyopaque, spans: []pb.Span) anyerror!void {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is ctx and what does it represent?
Is it a generic structure that has no well-defined field?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The *anyopaque indicates that any SpanExporter 's implementor can be the receiver of the exportSpans method.
It is usually used in the standard library.
https://github.com/ziglang/zig/blob/5647dd84c1930a70422fd80a7c2207c81cf858d8/lib/std/mem/Allocator.zig#L14

@inge4pres
Copy link
Collaborator

The test failure is with MetricReader 🙈
https://github.com/zig-o11y/opentelemetry-sdk/actions/runs/13083838017/job/36512216797?pr=13#step:4:11

I think that' fixed in my next PR, apologies for the noise

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.

2 participants