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
//! rustlavel-telescope: the debugging dashboard, enabled with one line.
//!
//! ```ignore
//! App::new()?
//! .routes(routes::web::routes)
//! .plugin(Telescope::default())
//! .serve()
//! .await
//! ```
//!
//! Telescope listens on the instrumentation bus core has carried since the
//! first release, keeps what it hears in a bounded in-memory ring buffer, and
//! serves a single self-contained page at `/telescope` that shows requests, the
//! queries and log lines each one produced, and how long everything took.
//!
//! # Why a ring buffer and not SQLite
//!
//! Laravel Telescope writes every entry to a database. That is the right answer
//! in PHP, where the process dies at the end of the request and there is
//! nowhere else to put anything. Rust has a process that lives for weeks, so
//! this crate makes two promises instead:
//!
//! **A debugging tool must never be the reason a request is slow.** Recording
//! an entry costs a redaction pass, a short mutex and a push onto a
//! `VecDeque` — no connection, no transaction, no `fsync`, no `await` on the
//! request's path. Optional persistence is a send into a queue that a writer
//! thread drains; the request never waits for a disk. The buffer is bounded, so
//! a server under load a week from now uses exactly the memory it uses today.
//!
//! **A debugging tool must never add a dependency to production builds.** The
//! whole crate depends on `rustlavel-core` and `rustlavel-http` and nothing
//! else — no embedded database, no serialisation framework, not even an async
//! runtime of its own. Persistence is JSON lines written with the JSON
//! implementation core already has: readable with `tail -f`, recoverable after
//! a `kill -9` at the cost of at most the last line, and compacted at boot so
//! the file can never outgrow the buffer it feeds.
//!
//! # What it records
//!
//! Whatever is dispatched. The framework emits `http.request`, `db.query` and
//! `log` today, and the roadmap promises `ai.call`, `queue.job` and
//! `mail.sent`; an [`Entry`] therefore stores an open field map rather than a
//! fixed enum, and every renderer degrades gracefully — a kind Telescope has
//! never seen still gets a readable summary, a stable colour, a duration and a
//! full field table.
//!
//! # Safety
//!
//! The dashboard shows SQL, log messages, and every field a package chose to
//! emit. So it refuses to mount in production unless someone explicitly says
//! otherwise (`telescope.enabled`, or [`Telescope::even_in_production`]), and
//! values under keys that look like credentials are replaced at record time —
//! before they reach the buffer, the API, or the journal on disk.
pub use Entry;
pub use Journal;
pub use Telescope;
pub use Recorder;
pub use ;
/// The event bus is process-global and tests run concurrently, so any test that
/// subscribes has to take this lock first — the same pattern the HTTP crate's
/// error page tests use for the process-wide debug flag.
pub