Skip to content

build: refactor, allow importing the package as a dependency #59

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

Merged
merged 6 commits into from
May 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 81 additions & 60 deletions build.zig
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const std = @import("std");
const protobuf = @import("protobuf");

pub fn build(b: *std.Build) void {
pub fn build(b: *std.Build) !void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});

Expand Down Expand Up @@ -47,18 +47,21 @@ pub fn build(b: *std.Build) void {
const gen_proto = b.step("gen-proto", "Generates Zig files from protobuf definitions");
gen_proto.dependOn(&protoc_step.step);

const sdk_lib = b.addStaticLibrary(.{
.name = "opentelemetry-sdk",
.root_module = b.createModule(.{
.root_source_file = b.path("src/sdk.zig"),
.target = target,
.optimize = optimize,
.strip = false,
.unwind_tables = .sync,
}),
const sdk_mod = b.addModule("sdk", .{
.root_source_file = b.path("src/sdk.zig"),
.target = target,
.optimize = optimize,
.strip = false,
.unwind_tables = .sync,
.imports = &.{
.{ .name = "protobuf", .module = protobuf_dep.module("protobuf") },
},
});

sdk_lib.root_module.addImport("protobuf", protobuf_dep.module("protobuf"));
const sdk_lib = b.addLibrary(.{
.name = "opentelemetry-sdk",
.root_module = sdk_mod,
});

b.installArtifact(sdk_lib);

Expand All @@ -68,26 +71,28 @@ pub fn build(b: *std.Build) void {
// Creates a step for unit testing the SDK.
// This only builds the test executable but does not run it.
const sdk_unit_tests = b.addTest(.{
.root_source_file = b.path("src/sdk.zig"),
.root_module = sdk_mod,
.target = target,
.optimize = optimize,
// Allow passing test filter using the build args.
.filters = b.args orelse &[0][]const u8{},
});
sdk_unit_tests.root_module.addImport("protobuf", protobuf_dep.module("protobuf"));

const run_sdk_unit_tests = b.addRunArtifact(sdk_unit_tests);

test_step.dependOn(&run_sdk_unit_tests.step);

// Examples
const examples_step = b.step("examples", "Build and run all examples");
examples_step.dependOn(&sdk_lib.step);

// TODO add examples for other signals
const metrics_examples = buildExamples(b, "examples/metrics", sdk_lib.root_module) catch |err| {
const metrics_examples = buildExamples(
b,
b.path(b.pathJoin(&.{ "examples", "metrics" })),
sdk_mod,
) catch |err| {
std.debug.print("Error building metrics examples: {}\n", .{err});
return;
return err;
};
defer b.allocator.free(metrics_examples);
for (metrics_examples) |step| {
Expand All @@ -97,96 +102,112 @@ pub fn build(b: *std.Build) void {

// Benchmarks
const benchmarks_step = b.step("benchmarks", "Build and run all benchmarks");
benchmarks_step.dependOn(&sdk_lib.step);

const benchmark_mod = benchmarks_dep.module("zbench");

const metrics_benchmarks = buildBenchmarks(b, "benchmarks/metrics", sdk_lib.root_module, benchmark_mod) catch |err| {
const metrics_benchmarks = buildBenchmarks(
b,
b.path(b.pathJoin(&.{ "benchmarks", "metrics" })),
sdk_mod,
benchmark_mod,
) catch |err| {
std.debug.print("Error building metrics benchmarks: {}\n", .{err});
return;
return err;
};
defer b.allocator.free(metrics_benchmarks);
for (metrics_benchmarks) |step| {
const run_metrics_benchmark = b.addRunArtifact(step);
benchmarks_step.dependOn(&run_metrics_benchmark.step);
}

// Documentation
// Documentation webiste with autodoc
const install_docs = b.addInstallDirectory(.{
.source_dir = sdk_lib.getEmittedDocs(),
.install_dir = .prefix,
.install_subdir = "docs",
});

const docs_step = b.step("docs", "Copy documentation artifacts to prefix path");
docs_step.dependOn(&sdk_lib.step);
docs_step.dependOn(&install_docs.step);
}

fn buildExamples(b: *std.Build, base_dir: []const u8, otel_mod: *std.Build.Module) ![]*std.Build.Step.Compile {
fn buildExamples(b: *std.Build, examples_dir: std.Build.LazyPath, otel_sdk_mod: *std.Build.Module) ![]*std.Build.Step.Compile {
var exes = std.ArrayList(*std.Build.Step.Compile).init(b.allocator);
errdefer exes.deinit();

var ex_dir = try std.fs.cwd().openDir(base_dir, .{ .iterate = true });
var ex_dir = try examples_dir.getPath3(b, null).openDir("", .{ .iterate = true });
defer ex_dir.close();

var ex_dir_iter = ex_dir.iterate();
while (try ex_dir_iter.next()) |file| {
// Get the file name.
// If it doesn't end in 'zig' then ignore.
const index = std.mem.lastIndexOfScalar(u8, file.name, '.') orelse continue;
if (index == 0) continue; // discard dotfiles
if (!std.mem.eql(u8, file.name[index + 1 ..], "zig")) continue;

const name = file.name[0..index];
const example = b.addExecutable(.{
.name = name,
.root_source_file = b.path(try std.fs.path.join(b.allocator, &.{ base_dir, file.name })),
.target = otel_mod.resolved_target.?,
// We set the optimization level to ReleaseSafe for examples
// because we want to have safety checks, and execute assertions.
.optimize = .ReleaseSafe,
});
example.root_module.addImport("opentelemetry-sdk", otel_mod);
try exes.append(example);
if (getZigFileName(file.name)) |name| {
const file_name = try examples_dir.join(b.allocator, file.name);

const b_mod = b.createModule(.{
.root_source_file = file_name,
.target = otel_sdk_mod.resolved_target.?,
// We set the optimization level to ReleaseSafe for examples
// because we want to have safety checks, and execute assertions.
.optimize = .ReleaseSafe,
.imports = &.{
.{ .name = "opentelemetry-sdk", .module = otel_sdk_mod },
},
});
try exes.append(b.addExecutable(.{
.name = name,
.root_module = b_mod,
}));
}
}

return exes.toOwnedSlice();
}

fn buildBenchmarks(
b: *std.Build,
base_dir: []const u8,
bench_dir: std.Build.LazyPath,
otel_mod: *std.Build.Module,
benchmark_mod: *std.Build.Module,
) ![]*std.Build.Step.Compile {
var bench_tests = std.ArrayList(*std.Build.Step.Compile).init(b.allocator);
errdefer bench_tests.deinit();

var test_dir = try std.fs.cwd().openDir(base_dir, .{ .iterate = true });
var test_dir = try bench_dir.getPath3(b, null).openDir("", .{ .iterate = true });
defer test_dir.close();

var iter = test_dir.iterate();
while (try iter.next()) |file| {
// Get the file name.
// If it doesn't end in 'zig' then ignore.
const index = std.mem.lastIndexOfScalar(u8, file.name, '.') orelse continue;
if (index == 0) continue; // discard dotfiles
if (!std.mem.eql(u8, file.name[index + 1 ..], "zig")) continue;

const name = file.name[0..index];
const benchmark = b.addTest(.{
.name = name,
.root_source_file = b.path(try std.fs.path.join(b.allocator, &.{ base_dir, file.name })),
.target = otel_mod.resolved_target.?,
// We set the optimization level to ReleaseFast for benchmarks
// because we want to have the best performance.
.optimize = .ReleaseFast,
});
benchmark.root_module.addImport("opentelemetry-sdk", otel_mod);
benchmark.root_module.addImport("benchmark", benchmark_mod);

try bench_tests.append(benchmark);
if (getZigFileName(file.name)) |name| {
const file_name = try bench_dir.join(b.allocator, file.name);

const b_mod = b.createModule(.{
.root_source_file = file_name,
.target = otel_mod.resolved_target.?,
// We set the optimization level to ReleaseFast for benchmarks
// because we want to have the best performance.
.optimize = .ReleaseFast,
.imports = &.{
.{ .name = "opentelemetry-sdk", .module = otel_mod },
.{ .name = "benchmark", .module = benchmark_mod },
},
});

try bench_tests.append(b.addTest(.{
.name = name,
.root_module = b_mod,
}));
}
}

return bench_tests.toOwnedSlice();
}

fn getZigFileName(file_name: []const u8) ?[]const u8 {
// Get the file name without extension, checking if it ends with '.zig'.
// If it doesn't end in 'zig' then ignore.
const index = std.mem.lastIndexOfScalar(u8, file_name, '.') orelse return null;
if (index == 0) return null; // discard dotfiles
if (!std.mem.eql(u8, file_name[index + 1 ..], "zig")) return null;
return file_name[0..index];
}
1 change: 1 addition & 0 deletions build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"build.zig.zon",
"src",
"examples",
"benchmarks",
"LICENSE",
"README.md",
},
Expand Down
3 changes: 3 additions & 0 deletions src/api/metrics/instrument.zig
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ pub const Instrument = struct {
u16 => .{ .Histogram_u16 = h },
u32 => .{ .Histogram_u32 = h },
u64 => .{ .Histogram_u64 = h },
i16 => .{ .Histogram_i16 = h },
i32 => .{ .Histogram_i32 = h },
i64 => .{ .Histogram_i64 = h },
f32 => .{ .Histogram_f32 = h },
f64 => .{ .Histogram_f64 = h },
else => {
Expand Down