-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuild.zig
More file actions
359 lines (322 loc) · 15.7 KB
/
Copy pathbuild.zig
File metadata and controls
359 lines (322 loc) · 15.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
const std = @import("std");
pub const Frontend = enum { stdio, httpz };
fn keepProfilingSymbols(m: *std.Build.Module) void {
m.omit_frame_pointer = false;
m.strip = false;
}
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
// Keep frame pointers + symbols so sampling profilers (Instruments) can
// unwind and name frames instead of dumping self-time onto
// <deduplicated_symbol>. Pair with -Doptimize=ReleaseFast for a realistic
// profile. Must be applied to every module in the hot path (deps included),
// since it's a per-module setting.
const profiling = b.option(bool, "profiling", "Keep frame pointers and symbols for profilers") orelse false;
const version = b.option([]const u8, "version", "Build version exposed in metrics") orelse "dev";
const commit = b.option([]const u8, "commit", "Build commit exposed in metrics") orelse "unknown";
// stdio is the default. httpz hands a batch of up to 16 requests to one
// pool thread, so one slow intake response parks the rest of that batch,
// and a health probe behind them times out — the ECS incident this suite
// reproduces (bench/matrix: c02, c05). stdio runs a task per connection,
// and measures 2 to 2.8 times the throughput of httpz once the intake is
// slow, with a p99.9 within 50 ms of its p50 instead of ten times it.
// httpz stays buildable and tested: bench/matrix runs every case against
// both.
const frontend = b.option(
Frontend,
"frontend",
"Inbound HTTP frontend (stdio = std.Io-native, httpz = event loop + worker pool)",
) orelse .stdio;
const build_options = b.addOptions();
build_options.addOption([]const u8, "version", version);
build_options.addOption([]const u8, "commit", commit);
build_options.addOption(Frontend, "frontend", frontend);
// ==========================================================================
// Dependencies
// ==========================================================================
const zimdjson = b.dependency("zimdjson", .{
.target = target,
.optimize = optimize,
});
const zbench_dep = b.dependency("zbench", .{
.target = target,
.optimize = optimize,
});
const policy_dep = b.dependency("policy_zig", .{
.target = target,
.optimize = optimize,
});
const metrics_dep = b.dependency("metrics", .{
.target = target,
.optimize = optimize,
});
const httpz_dep = b.dependency("httpz", .{
.target = target,
.optimize = optimize,
});
const httpz_mod = httpz_dep.module("httpz");
// Shared modules from policy-zig ensure type identity across boundaries.
const proto_mod = policy_dep.module("proto");
const o11y_mod = policy_dep.module("observability");
// Optional extensions module (pulls in the z3 S3 client). Only edge code
// that wires s3-dump imports it.
const ext_mod = policy_dep.module("extensions");
// ==========================================================================
// Edge Library Module
// ==========================================================================
const mod = b.addModule("edge", .{
.root_source_file = b.path("src/root.zig"),
.target = target,
.imports = &.{
.{ .name = "proto", .module = proto_mod },
.{ .name = "zimdjson", .module = zimdjson.module("zimdjson") },
.{ .name = "policy_zig", .module = policy_dep.module("policy_zig") },
.{ .name = "o11y", .module = o11y_mod },
.{ .name = "extensions", .module = ext_mod },
.{ .name = "metrics_zig", .module = metrics_dep.module("metrics") },
.{ .name = "httpz", .module = httpz_mod },
},
});
mod.addOptions("build_options", build_options);
if (profiling) {
for ([_]*std.Build.Module{
mod,
proto_mod,
o11y_mod,
policy_dep.module("policy_zig"),
zimdjson.module("zimdjson"),
metrics_dep.module("metrics"),
httpz_mod,
}) |m| keepProfilingSymbols(m);
}
// ==========================================================================
// Main Executable
// ==========================================================================
const exe = b.addExecutable(.{
.name = "edge",
.root_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
.imports = &.{
.{ .name = "edge", .module = mod },
},
}),
});
exe.root_module.addImport("proto", proto_mod);
exe.root_module.addImport("zimdjson", zimdjson.module("zimdjson"));
exe.root_module.addImport("policy_zig", policy_dep.module("policy_zig"));
exe.root_module.addImport("o11y", o11y_mod);
exe.root_module.addImport("extensions", ext_mod);
exe.root_module.addImport("metrics_zig", metrics_dep.module("metrics"));
exe.root_module.addImport("httpz", httpz_mod);
exe.root_module.addOptions("build_options", build_options);
exe.root_module.link_libc = true;
exe.root_module.linkSystemLibrary("z", .{});
exe.root_module.linkSystemLibrary("zstd", .{});
if (profiling) keepProfilingSymbols(exe.root_module);
b.installArtifact(exe);
// ==========================================================================
// Distribution Builds
// ==========================================================================
const distributions = .{
.{ "datadog", "src/datadog_main.zig", "Datadog ingestion" },
.{ "otlp", "src/otlp_main.zig", "OpenTelemetry (OTLP) ingestion" },
.{ "prometheus", "src/prometheus_main.zig", "Prometheus metrics scraping" },
.{ "tail", "src/edge_tail_main.zig", "Log tailing" },
.{ "edge", "src/main.zig", "Full distribution (OTLP, Datadog & Prometheus)" },
.{ "lambda", "src/lambda_main.zig", "AWS Lambda extension (Datadog)" },
};
inline for (distributions) |dist| {
const name = dist[0];
const source = dist[1];
const desc = dist[2];
const dist_exe = b.addExecutable(.{
.name = "edge-" ++ name,
.root_module = b.createModule(.{
.root_source_file = b.path(source),
.target = target,
.optimize = optimize,
}),
});
dist_exe.root_module.addImport("proto", proto_mod);
dist_exe.root_module.addImport("zimdjson", zimdjson.module("zimdjson"));
dist_exe.root_module.addImport("policy_zig", policy_dep.module("policy_zig"));
dist_exe.root_module.addImport("o11y", o11y_mod);
dist_exe.root_module.addImport("extensions", ext_mod);
dist_exe.root_module.addImport("metrics_zig", metrics_dep.module("metrics"));
dist_exe.root_module.addImport("httpz", httpz_mod);
dist_exe.root_module.addOptions("build_options", build_options);
dist_exe.root_module.link_libc = true;
dist_exe.root_module.linkSystemLibrary("z", .{});
dist_exe.root_module.linkSystemLibrary("zstd", .{});
if (profiling) keepProfilingSymbols(dist_exe.root_module);
const dist_step = b.step(name, "Build the " ++ name ++ " distribution (" ++ desc ++ ")");
dist_step.dependOn(&b.addInstallArtifact(dist_exe, .{}).step);
const run_dist_step = b.step("run-" ++ name, "Run the " ++ name ++ " distribution");
const run_dist_cmd = b.addRunArtifact(dist_exe);
run_dist_step.dependOn(&run_dist_cmd.step);
run_dist_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_dist_cmd.addArgs(args);
}
}
// ==========================================================================
// Run Step
// ==========================================================================
const run_step = b.step("run", "Run the app");
const run_cmd = b.addRunArtifact(exe);
run_step.dependOn(&run_cmd.step);
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_cmd.addArgs(args);
}
// ==========================================================================
// Tests
// ==========================================================================
const mod_tests = b.addTest(.{
.root_module = mod,
});
mod_tests.root_module.link_libc = true;
mod_tests.root_module.linkSystemLibrary("z", .{});
mod_tests.root_module.linkSystemLibrary("zstd", .{});
mod_tests.root_module.addImport("metrics_zig", metrics_dep.module("metrics"));
mod_tests.root_module.addOptions("build_options", build_options);
// Benchmark fixture embedded by test-only code in src/signals/otlp/metrics.zig.
// It lives under bench/ (outside the src package), so @embedFile needs it wired
// in as a named module import rather than a relative path.
mod_tests.root_module.addAnonymousImport("otlp_metrics_benchmark_pb", .{
.root_source_file = b.path("bench/scaling/payloads/otlp-metrics.pb"),
});
const run_mod_tests = b.addRunArtifact(mod_tests);
const test_step = b.step("test", "Run tests");
test_step.dependOn(&run_mod_tests.step);
// The echo server is its own module (src/bench is outside the src
// package), so its tests need their own artifact or they never run. The
// matrix trusts this binary to behave like an intake, which makes its
// parsing and its `/stats` output worth a check.
const echo_tests = b.addTest(.{
.root_module = b.createModule(.{
.root_source_file = b.path("src/bench/echo_server.zig"),
.target = target,
.optimize = optimize,
}),
});
echo_tests.root_module.addImport("head_repair", b.createModule(.{
.root_source_file = b.path("src/frontend/stdio/head_repair.zig"),
.target = target,
.optimize = optimize,
}));
test_step.dependOn(&b.addRunArtifact(echo_tests).step);
// Real-storage smoke test for the s3-dump extension, filtered to the MinIO
// e2e test. Excluded from `test` (it needs a live backend); driven by
// `task test:s3-e2e`, which starts MinIO, creates the bucket, and sets the
// S3 env vars this test reads.
const s3_e2e_tests = b.addTest(.{
.root_module = mod,
.filters = &.{"e2e minio"},
});
s3_e2e_tests.root_module.link_libc = true;
s3_e2e_tests.root_module.linkSystemLibrary("z", .{});
s3_e2e_tests.root_module.linkSystemLibrary("zstd", .{});
s3_e2e_tests.root_module.addImport("metrics_zig", metrics_dep.module("metrics"));
s3_e2e_tests.root_module.addOptions("build_options", build_options);
s3_e2e_tests.root_module.addAnonymousImport("otlp_metrics_benchmark_pb", .{
.root_source_file = b.path("bench/scaling/payloads/otlp-metrics.pb"),
});
const run_s3_e2e_tests = b.addRunArtifact(s3_e2e_tests);
const s3_e2e_step = b.step("test-s3-e2e", "Run the s3-dump MinIO smoke test (needs S3 env vars)");
s3_e2e_step.dependOn(&run_s3_e2e_tests.step);
// ==========================================================================
// Benchmark Tools
// ==========================================================================
const echo_server = b.addExecutable(.{
.name = "echo-server",
.root_module = b.createModule(.{
.root_source_file = b.path("src/bench/echo_server.zig"),
.target = target,
.optimize = optimize,
}),
});
// The fake intake must take the heads a real intake takes, so it shares
// the frontend's head repair rather than keeping its own copy.
echo_server.root_module.addImport("head_repair", b.createModule(.{
.root_source_file = b.path("src/frontend/stdio/head_repair.zig"),
.target = target,
.optimize = optimize,
}));
const echo_step = b.step("echo-server", "Build the echo server for benchmarking");
echo_step.dependOn(&b.addInstallArtifact(echo_server, .{}).step);
// Upstream connection-pool poisoning harness: reproduces the stale-keepalive
// poison (ziglang/zig#30165 send-side) and verifies the eviction fix.
const pool_harness = b.addExecutable(.{
.name = "upstream-pool-harness",
.root_module = b.createModule(.{
.root_source_file = b.path("src/bench/upstream_pool_harness.zig"),
.target = target,
.optimize = optimize,
}),
});
const pool_harness_step = b.step("upstream-pool-harness", "Verify upstream pool eviction+retry against real edge");
const run_pool_harness = b.addRunArtifact(pool_harness);
run_pool_harness.step.dependOn(b.getInstallStep()); // harness spawns zig-out/bin/edge
pool_harness_step.dependOn(&run_pool_harness.step);
// Datadog log search/filter microbenchmark (zbench).
const datadog_log_bench = b.addExecutable(.{
.name = "datadog-log-bench",
.root_module = b.createModule(.{
.root_source_file = b.path("src/bench/datadog_log_bench.zig"),
.target = target,
.optimize = optimize,
.imports = &.{
.{ .name = "edge", .module = mod },
.{ .name = "zbench", .module = zbench_dep.module("zbench") },
.{ .name = "proto", .module = proto_mod },
.{ .name = "o11y", .module = o11y_mod },
},
}),
});
datadog_log_bench.root_module.addAnonymousImport("datadog_wrapped_log", .{
.root_source_file = b.path("bench/datadog/payloads/wrapped_log.json"),
});
// The bench has a --profile mode for attaching Instruments; always keep
// frame pointers + symbols so ReleaseFast stacks symbolicate.
keepProfilingSymbols(datadog_log_bench.root_module);
datadog_log_bench.root_module.link_libc = true;
datadog_log_bench.root_module.linkSystemLibrary("z", .{});
datadog_log_bench.root_module.linkSystemLibrary("zstd", .{});
const datadog_log_bench_step = b.step("datadog-log-bench", "Run the Datadog log eval matrix benchmark");
const run_datadog_log_bench = b.addRunArtifact(datadog_log_bench);
// Forward CLI args (e.g. `zig build datadog-log-bench -- --profile plain/none 30`)
// and install the binary so a profiler can be attached to it directly.
if (b.args) |args| run_datadog_log_bench.addArgs(args);
datadog_log_bench_step.dependOn(&run_datadog_log_bench.step);
datadog_log_bench_step.dependOn(&b.addInstallArtifact(datadog_log_bench, .{}).step);
// JSON-array framer microbenchmark (zbench).
const json_framer_bench = b.addExecutable(.{
.name = "json-framer-bench",
.root_module = b.createModule(.{
.root_source_file = b.path("src/bench/json_framer_bench.zig"),
.target = target,
.optimize = optimize,
.imports = &.{
.{ .name = "edge", .module = mod },
.{ .name = "zbench", .module = zbench_dep.module("zbench") },
},
}),
});
json_framer_bench.root_module.link_libc = true;
json_framer_bench.root_module.linkSystemLibrary("z", .{});
json_framer_bench.root_module.linkSystemLibrary("zstd", .{});
const json_framer_bench_step = b.step("json-framer-bench", "Run the JSON-array framer benchmark");
const run_json_framer_bench = b.addRunArtifact(json_framer_bench);
json_framer_bench_step.dependOn(&run_json_framer_bench.step);
const run_echo_step = b.step("run-echo-server", "Run the echo server");
const run_echo_cmd = b.addRunArtifact(echo_server);
run_echo_step.dependOn(&run_echo_cmd.step);
run_echo_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_echo_cmd.addArgs(args);
}
}