Skip to content

Commit 12cad8a

Browse files
committed
Add navigate telemetry
1 parent cf56a6b commit 12cad8a

File tree

11 files changed

+63
-46
lines changed

11 files changed

+63
-46
lines changed

.github/workflows/e2e-test.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ jobs:
6464
env:
6565
MAX_MEMORY: 28000
6666
MAX_AVG_DURATION: 24
67+
LIGHTPANDA_DISABLE_TELEMETRY: true
6768

6869
runs-on: ubuntu-latest
6970

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ await context.close();
111111
await browser.disconnect();
112112
```
113113

114+
### Telemetry
115+
By default, Lightpanda collects and sends usage telemetry. This can be disabled by setting an environment variable `LIGHTPANDA_DISABLE_TELEMETRY=true`. You can read Lightpanda's privacy policy at: [https://lightpanda.io/privacy-policy](https://lightpanda.io/privacy-policy).
116+
114117
## Status
115118

116119
Lightpanda is still a work in progress and is currently at a Beta stage.

src/app.zig

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,30 @@ const Telemetry = @import("telemetry/telemetry.zig").Telemetry;
77
// Container for global state / objects that various parts of the system
88
// might need.
99
pub const App = struct {
10+
loop: *Loop,
11+
allocator: Allocator,
1012
telemetry: Telemetry,
1113

12-
pub fn init(allocator: Allocator, loop: *Loop) !App {
14+
pub fn init(allocator: Allocator) !App {
15+
const loop = try allocator.create(Loop);
16+
errdefer allocator.destroy(loop);
17+
18+
loop.* = try Loop.init(allocator);
19+
errdefer loop.deinit();
20+
1321
const telemetry = Telemetry.init(allocator, loop);
1422
errdefer telemetry.deinit();
1523

1624
return .{
25+
.loop = loop,
26+
.allocator = allocator,
1727
.telemetry = telemetry,
1828
};
1929
}
2030

2131
pub fn deinit(self: *App) void {
2232
self.telemetry.deinit();
33+
self.loop.deinit();
34+
self.allocator.destroy(self.loop);
2335
}
2436
};

src/browser/browser.zig

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ const Loop = jsruntime.Loop;
3333
const Env = jsruntime.Env;
3434
const Module = jsruntime.Module;
3535

36+
const App = @import("../app.zig").App;
3637
const apiweb = @import("../apiweb.zig");
3738

3839
const Window = @import("../html/window.zig").Window;
@@ -59,21 +60,19 @@ pub const user_agent = "Lightpanda/1.0";
5960
// A browser contains only one session.
6061
// TODO allow multiple sessions per browser.
6162
pub const Browser = struct {
62-
loop: *Loop,
63+
app: *App,
6364
session: ?*Session,
64-
allocator: Allocator,
6565
session_pool: SessionPool,
6666

6767
const SessionPool = std.heap.MemoryPool(Session);
6868

6969
const uri = "about:blank";
7070

71-
pub fn init(allocator: Allocator, loop: *Loop) Browser {
71+
pub fn init(app: *App) Browser {
7272
return .{
73-
.loop = loop,
73+
.app = app,
7474
.session = null,
75-
.allocator = allocator,
76-
.session_pool = SessionPool.init(allocator),
75+
.session_pool = SessionPool.init(app.allocator),
7776
};
7877
}
7978

@@ -86,7 +85,7 @@ pub const Browser = struct {
8685
self.closeSession();
8786

8887
const session = try self.session_pool.create();
89-
try Session.init(session, self.allocator, ctx, self.loop, uri);
88+
try Session.init(session, self.app, ctx, uri);
9089
self.session = session;
9190
return session;
9291
}
@@ -111,6 +110,8 @@ pub const Browser = struct {
111110
// You can create successively multiple pages for a session, but you must
112111
// deinit a page before running another one.
113112
pub const Session = struct {
113+
app: *App,
114+
114115
// allocator used to init the arena.
115116
allocator: Allocator,
116117

@@ -138,8 +139,10 @@ pub const Session = struct {
138139

139140
jstypes: [Types.len]usize = undefined,
140141

141-
fn init(self: *Session, allocator: Allocator, ctx: anytype, loop: *Loop, uri: []const u8) !void {
142+
fn init(self: *Session, app: *App, ctx: anytype, uri: []const u8) !void {
143+
const allocator = app.allocator;
142144
self.* = .{
145+
.app = app,
143146
.uri = uri,
144147
.env = undefined,
145148
.inspector = undefined,
@@ -153,7 +156,7 @@ pub const Session = struct {
153156

154157
const arena = self.arena.allocator();
155158

156-
Env.init(&self.env, arena, loop, null);
159+
Env.init(&self.env, arena, app.loop, null);
157160
errdefer self.env.deinit();
158161
try self.env.load(&self.jstypes);
159162

@@ -339,6 +342,7 @@ pub const Page = struct {
339342
// - auxData: extra data forwarded to the Inspector
340343
// see Inspector.contextCreated
341344
pub fn navigate(self: *Page, uri: []const u8, auxData: ?[]const u8) !void {
345+
self.session.app.telemetry.record(.{ .navigate = {} });
342346
const alloc = self.arena.allocator();
343347

344348
log.debug("starting GET {s}", .{uri});

src/cdp/cdp.zig

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@ const Allocator = std.mem.Allocator;
2121
const json = std.json;
2222

2323
const dom = @import("dom.zig");
24-
const Loop = @import("jsruntime").Loop;
25-
// const Client = @import("../server.zig").Client;
24+
const App = @import("../app.zig").App;
2625
const asUint = @import("../str/parser.zig").asUint;
2726

2827
const log = std.log.scoped(.cdp);
@@ -78,10 +77,11 @@ pub fn CDPT(comptime TypeProvider: type) type {
7877
pub const Browser = TypeProvider.Browser;
7978
pub const Session = TypeProvider.Session;
8079

81-
pub fn init(allocator: Allocator, client: *TypeProvider.Client, loop: anytype) Self {
80+
pub fn init(app: *App, client: *TypeProvider.Client) Self {
81+
const allocator = app.allocator;
8282
return .{
8383
.client = client,
84-
.browser = Browser.init(allocator, loop),
84+
.browser = Browser.init(app),
8585
.session = null,
8686
.allocator = allocator,
8787
.url = URL_BASE,

src/cdp/testing.zig

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const Testing = @This();
77

88
const cdp = @import("cdp.zig");
99
const parser = @import("netsurf");
10+
const App = @import("../app.zig").App;
1011

1112
pub const expectEqual = std.testing.expectEqual;
1213
pub const expectError = std.testing.expectError;
@@ -15,8 +16,8 @@ pub const expectString = std.testing.expectEqualStrings;
1516
const Browser = struct {
1617
session: ?Session = null,
1718

18-
pub fn init(_: Allocator, loop: anytype) Browser {
19-
_ = loop;
19+
pub fn init(app: *App) Browser {
20+
_ = app;
2021
return .{};
2122
}
2223

@@ -90,6 +91,7 @@ const TestCDP = cdp.CDPT(struct {
9091
});
9192

9293
const TestContext = struct {
94+
app: App,
9395
client: ?Client = null,
9496
cdp_: ?TestCDP = null,
9597
arena: std.heap.ArenaAllocator,
@@ -98,6 +100,7 @@ const TestContext = struct {
98100
if (self.cdp_) |*c| {
99101
c.deinit();
100102
}
103+
self.app.deinit();
101104
self.arena.deinit();
102105
}
103106

@@ -106,7 +109,7 @@ const TestContext = struct {
106109
self.client = Client.init(self.arena.allocator());
107110
// Don't use the arena here. We want to detect leaks in CDP.
108111
// The arena is only for test-specific stuff
109-
self.cdp_ = TestCDP.init(std.testing.allocator, &self.client.?, "dummy-loop");
112+
self.cdp_ = TestCDP.init(&self.app, &self.client.?);
110113
}
111114
return &self.cdp_.?;
112115
}
@@ -165,6 +168,7 @@ const TestContext = struct {
165168

166169
pub fn context() TestContext {
167170
return .{
171+
.app = App.init(std.testing.allocator) catch unreachable,
168172
.arena = std.heap.ArenaAllocator.init(std.testing.allocator),
169173
};
170174
}

src/main.zig

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -70,27 +70,20 @@ pub fn main() !void {
7070
return args.printUsageAndExit(false);
7171
};
7272

73-
var loop = try jsruntime.Loop.init(alloc);
74-
defer loop.deinit();
75-
76-
var app = try @import("app.zig").App.init(alloc, &loop);
73+
var app = try @import("app.zig").App.init(alloc);
7774
defer app.deinit();
7875
app.telemetry.record(.{ .run = .{ .mode = .serve, .version = version } });
7976

8077
const timeout = std.time.ns_per_s * @as(u64, opts.timeout);
81-
server.run(alloc, address, timeout, &loop, &app) catch |err| {
78+
server.run(&app, address, timeout) catch |err| {
8279
log.err("Server error", .{});
8380
return err;
8481
};
8582
},
8683
.fetch => |opts| {
8784
log.debug("Fetch mode: url {s}, dump {any}", .{ opts.url, opts.dump });
8885

89-
// loop
90-
var loop = try jsruntime.Loop.init(alloc);
91-
defer loop.deinit();
92-
93-
var app = try @import("app.zig").App.init(alloc, &loop);
86+
var app = try @import("app.zig").App.init(alloc);
9487
defer app.deinit();
9588
app.telemetry.record(.{ .run = .{ .mode = .fetch, .version = version } });
9689

@@ -99,7 +92,7 @@ pub fn main() !void {
9992
defer vm.deinit();
10093

10194
// browser
102-
var browser = Browser.init(alloc, &loop);
95+
var browser = Browser.init(&app);
10396
defer browser.deinit();
10497

10598
var session = try browser.newSession({});

src/server.zig

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@ const Server = struct {
8080
self.send_pool.deinit();
8181
self.client_pool.deinit();
8282
self.completion_state_pool.deinit();
83-
self.allocator.free(self.json_version_response);
8483
}
8584

8685
fn queueAccept(self: *Server) void {
@@ -597,7 +596,7 @@ fn ClientT(comptime S: type, comptime C: type) type {
597596
};
598597

599598
self.mode = .websocket;
600-
self.cdp = C.init(self.server.allocator, self, self.server.loop);
599+
self.cdp = C.init(self.server.app, self);
601600
return self.sendAlloc(arena, response);
602601
}
603602

@@ -1026,11 +1025,9 @@ fn websocketHeader(buf: []u8, op_code: OpCode, payload_len: usize) []const u8 {
10261025
}
10271026

10281027
pub fn run(
1029-
allocator: Allocator,
1028+
app: *App,
10301029
address: net.Address,
10311030
timeout: u64,
1032-
loop: *jsruntime.Loop,
1033-
app: *App,
10341031
) !void {
10351032
// create socket
10361033
const flags = posix.SOCK.STREAM | posix.SOCK.CLOEXEC | posix.SOCK.NONBLOCK;
@@ -1053,14 +1050,17 @@ pub fn run(
10531050
const vm = jsruntime.VM.init();
10541051
defer vm.deinit();
10551052

1053+
var loop = app.loop;
1054+
const allocator = app.allocator;
10561055
const json_version_response = try buildJSONVersionResponse(allocator, address);
1056+
defer allocator.free(json_version_response);
10571057

10581058
var server = Server{
10591059
.app = app,
10601060
.loop = loop,
10611061
.timeout = timeout,
10621062
.listener = listener,
1063-
.allocator = allocator,
1063+
.allocator = app.allocator,
10641064
.close_completion = undefined,
10651065
.accept_completion = undefined,
10661066
.json_version_response = json_version_response,
@@ -1739,7 +1739,7 @@ fn assertWebSocketMessage(
17391739
}
17401740

17411741
const MockServer = struct {
1742-
loop: *jsruntime.Loop = undefined,
1742+
app: *App = undefined,
17431743
closed: bool = false,
17441744

17451745
// record the messages we sent to the client
@@ -1782,8 +1782,8 @@ const MockCDP = struct {
17821782

17831783
allocator: Allocator = testing.allocator,
17841784

1785-
fn init(_: Allocator, client: anytype, loop: *jsruntime.Loop) MockCDP {
1786-
_ = loop;
1785+
fn init(app: *App, client: anytype) MockCDP {
1786+
_ = app;
17871787
_ = client;
17881788
return .{};
17891789
}

src/telemetry/lightpanda.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const Client = @import("asyncio").Client;
77

88
const log = std.log.scoped(.telemetry);
99

10-
const URL = "https://stats.lightpanda.io";
10+
const URL = "https://httpbin.io/post";
1111

1212
pub const LightPanda = struct {
1313
uri: std.Uri,

src/telemetry/telemetry.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const log = std.log.scoped(.telemetry);
1010
const ID_FILE = "lightpanda.id";
1111

1212
pub const Telemetry = TelemetryT(blk: {
13-
// if (builtin.mode == .Debug or builtin.is_test) break :blk NoopProvider;
13+
if (builtin.mode == .Debug or builtin.is_test) break :blk NoopProvider;
1414
break :blk @import("lightpanda.zig").LightPanda;
1515
});
1616

0 commit comments

Comments
 (0)