mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-09-18 09:54:36 -04:00
ops: Add prometheus metrics
Adds a /metrics endpoint in serve mode. Can be disabled via --disable-metrics. In fetch, dumps the metrics if --metrics is specified (defaults to false). None of the metrics being collected are on a hot path, so they're just always collected using atomic operations (i.e. no `if (!enabled) return;`). Because the operations are cheap and infrequent enough not to matter. The one place I want to add more metrics is in HttpClient (bytes, status, counts, ...) but after the pending HttpClient-related PR is merged. ./lightpanda fetch --log-level fatal --metrics "https://lightpanda.io/" ``` build_info{version="1.0.0-dev.7837+70493ce35"} 1 cdp_connections_total 0 cdp_connection_limit_total 0 cdp_active_connections 0 cdp_commands_total 0 cdp_unknown_commands_total 0 js_heap_limits_total 0 script_errors_total 0 arena_hit_total{size="tiny"} 908 arena_hit_total{size="small"} 35 arena_hit_total{size="medium"} 0 arena_hit_total{size="large"} 27 arena_miss_total{size="tiny"} 193 arena_miss_total{size="small"} 31 arena_miss_total{size="medium"} 5 arena_miss_total{size="large"} 23 navigate_total{type="page"} 1 navigate_total{type="iframe"} 0 navigate_total{type="popup"} 0 js_heap_size_bytes_bucket{le="4194304"} 0 js_heap_size_bytes_bucket{le="8388608"} 0 js_heap_size_bytes_bucket{le="16777216"} 1 js_heap_size_bytes_bucket{le="33554432"} 1 js_heap_size_bytes_bucket{le="67108864"} 1 js_heap_size_bytes_bucket{le="134217728"} 1 js_heap_size_bytes_bucket{le="268435456"} 1 js_heap_size_bytes_bucket{le="536870912"} 1 js_heap_size_bytes_bucket{le="+Inf"} 1 js_heap_size_bytes_sum 11223040 js_heap_size_bytes_count 1 ```
This commit is contained in:
14 files changed
+377
-24
No files matched your search
+24
-4
@@ -156,6 +156,7 @@ fn spawnWorker(self: *Server, socket: posix.socket_t) !void {
|
||||
while (current < self.max_connections) {
|
||||
current = self.active_threads.cmpxchgWeak(current, current + 1, .monotonic, .monotonic) orelse break;
|
||||
} else {
|
||||
lp.metrics.cdp_connection_limit.incr();
|
||||
return error.MaxThreadsReached;
|
||||
}
|
||||
errdefer _ = self.active_threads.fetchSub(1, .monotonic);
|
||||
@@ -218,6 +219,12 @@ fn handleConnection(self: *Server, socket: posix.socket_t) void {
|
||||
return;
|
||||
}
|
||||
|
||||
// only count websocket (i.e. CDP) connections, not HTTP requests like
|
||||
// /json/version probes or /metrics scrapes
|
||||
lp.metrics.cdp_connections.incr();
|
||||
lp.metrics.cdp_active_connections.incr();
|
||||
defer lp.metrics.cdp_active_connections.decr();
|
||||
|
||||
{
|
||||
// Transition from .handshake state to .live
|
||||
// Lock needed even though the main thread hasn't seen this yet because
|
||||
@@ -551,6 +558,18 @@ test "server: get /json/version" {
|
||||
}
|
||||
}
|
||||
|
||||
test "server: get /metrics" {
|
||||
var c = try createTestClient();
|
||||
defer c.deinit();
|
||||
|
||||
const res = try c.httpRequest("GET /metrics HTTP/1.1\r\n\r\n");
|
||||
std.debug.print("1\n", .{});
|
||||
try testing.expect(std.mem.startsWith(u8, res, "HTTP/1.1 200 OK\r\n"));
|
||||
try testing.expect(std.mem.indexOf(u8, res, "Content-Type: text/plain; version=0.0.4") != null);
|
||||
try testing.expect(std.mem.indexOf(u8, res, "build_info{version=") != null);
|
||||
try testing.expect(std.mem.indexOf(u8, res, "# TYPE cdp_connections_total counter") != null);
|
||||
}
|
||||
|
||||
fn assertHTTPError(
|
||||
comptime expected_status: u16,
|
||||
comptime expected_body: []const u8,
|
||||
@@ -648,7 +667,7 @@ fn createTestClient() !TestClient {
|
||||
|
||||
const TestClient = struct {
|
||||
stream: std.net.Stream,
|
||||
buf: [1024]u8 = undefined,
|
||||
buf: [4096]u8 = undefined,
|
||||
reader: WS.Reader(false),
|
||||
|
||||
const WS = @import("network/WS.zig");
|
||||
@@ -664,10 +683,11 @@ const TestClient = struct {
|
||||
var pos: usize = 0;
|
||||
var total_length: ?usize = null;
|
||||
while (true) {
|
||||
pos += try self.stream.read(self.buf[pos..]);
|
||||
if (pos == 0) {
|
||||
return error.NoMoreData;
|
||||
const n = try self.stream.read(self.buf[pos..]);
|
||||
if (n == 0) {
|
||||
return if (pos == self.buf.len) error.MessageTooLarge else error.NoMoreData;
|
||||
}
|
||||
pos += n;
|
||||
const response = self.buf[0..pos];
|
||||
if (total_length == null) {
|
||||
const header_end = std.mem.indexOf(u8, response, "\r\n\r\n") orelse continue;
|
||||
|
||||
Reference in new issue
Block a user