You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: blueprints/observability-for-user-apps.html.md
+10-10Lines changed: 10 additions & 10 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -33,11 +33,11 @@ This is handy for SREs, but not necessary for your end‑users.
33
33
34
34
## Streaming Fly app logs to your end users
35
35
36
-
Streaming logs straight to your users gives them instant, first-person insight into what their code is doing—developers see exactly what the runtime sees, in real time, without leaving your product or juggling extra tooling.
36
+
Streaming live logs straight to your users gives them insight into what their code is doing—developers see exactly what the runtime sees, in real time, without leaving your product or juggling extra tooling.
37
37
38
38
### Connecting to the NATS Log Stream
39
39
40
-
Every Fly organization has access to **NATS** which carries the logs for its apps. The server is available at the well-known address `[fdaa::3]:4223`. To connect to this endpoint, you must do so from within the Fly network: for example, from code running in a Fly app (like your telemetry forwarder or router) or from your local machine over a WireGuard connection.
40
+
Every Fly organization has access to **NATS** which carries the logs for its apps. The server is available at the well-known address `[fdaa::3]:4223`. To connect to this endpoint, you must do so from within the Fly network—for example, from code running in a Fly app (like your telemetry forwarder or router) or from your local machine over a WireGuard connection.
41
41
42
42
Using the NATS JavaScript client, you could connect as follows:
user:"sandwhich-expert", // your Fly org slug (example)
49
+
user:"sandwich-expert", // your Fly org slug (example)
50
50
pass:process.env.ACCESS_TOKEN// your Fly access token (read-only)
51
51
});
52
52
@@ -65,7 +65,7 @@ Logs in the NATS stream are organized by **subject**. The subject format for Fly
65
65
logs.<app_name>.<region>.<machine_id>
66
66
```
67
67
68
-
For example, if you have an application named `sandwich` and it's running in region `dfw`, you might see subjects like `logs.sandwich.dfw.abc123` (where `abc123` is the Machine ID). You can subscribe at varying levels of granularity using NATS wildcards:
68
+
For example, if you have an application named `panini-786` and it's running in region `dfw`, you might see subjects like `logs.panini-786.dfw.d896d7c609dd68` (where `d896d7c609dd68` is the Machine ID). You can subscribe at varying levels of granularity using NATS wildcards:
69
69
70
70
| Subject Pattern | Description |
71
71
|----------------|-------------|
@@ -78,22 +78,22 @@ In practice, to stream all logs for a given user's app, you'll subscribe to the
78
78
79
79
### A Real-World Example
80
80
81
-
[**NATstream**](https://natstream.fly.dev/) is a reference app that streams logs from your Fly apps right back to the browser. It connects to NATS and turns those events into a live feed at a simple HTTP `/logs` endpoint using Server-Sent Events (SSE). Developers could log in to your product and watch their app's logs flow in real time, without needing separate logging tools or the Fly CLI. The app keeps things high-level and lightweight—there's no deep framework complexity here, just a straightforward example of hooking into Fly's log pipeline and broadcasting events to the browser. You can rip out the relevant parts, or fork it as a foundation for your own developer-facing live log streaming service.
81
+
[**NATstream**](https://natstream.fly.dev/) is a reference app that streams logs from your Fly apps right back to the browser. It connects to NATS and turns those events into a live feed at a simple HTTP `/logs` endpoint using Server-Sent Events (SSE). Developers could log in to your product and watch their app's logs flow in real time, without needing separate logging tools or the Fly CLI. The app keeps things high-level and lightweight—there's no deep framework complexity here, just a straightforward example of hooking into Fly's log pipeline and broadcasting events to the browser.
<imgsrc="/static/images/natstream.webp"alt="Screenshot of the NATstream open source app UI"class="w:full h:full fit:cover">
85
85
</figure>
86
86
87
-
You could build this logic into your existing app, using the NATstream implementation as a guide, or more robustly you could run a separate log "router" app that handles authentications and streaming on a per user, per app basis. This would be especially useful if streaming logs to a CLI.
87
+
You can fork it as a foundation for your own developer-facing live log streaming service, or rip out the relevant parts and build this logic into your existing app, using the NATstream implementation as a guide. More robustly, you could run a separate log "router" app that handles authentications and streaming on a per user, per app basis. This would be especially useful if streaming logs to a CLI.
88
88
89
89
---
90
90
91
91
## Building a Central Log Router Service
92
92
93
-
Create a Fly "log router" app that sits between Fly's NATS telemetry stream, your product and your developers. Because each customer already has their own Fly app, every user's logs appear on a unique subject (`logs.<app>.>`), so multi-tenancy is solved by design: subscribe only to the subject that matches the requesting developer's app and you'll never mix data between users.
93
+
Create a Fly "log router" app that sits between Fly's NATS telemetry stream, your product and your developers. Because each customer already has their own Fly app, every user's logs appear on a unique subject (`logs.<app>.>`), so multi-tenancy is solved by design—subscribe only to the subject that matches the requesting developer's app and you'll never mix data between users.
94
94
95
95
<divclass="note icon">
96
-
**Note**: Your router service should enforce that a user can only request the logs for the app(s) they own. This means your routing logic needs an access control check (e.g. based on the authenticated user's ID matching the app name or an internal mapping). Never trust the client to only ask for their own app – always validate on the server. Fortunately, if you've structured your platform as one Fly app per user, it's straightforward to maintain a mapping from user account to Fly app name and use that for authorization.
96
+
**Note**: Your router service should enforce that a user can only request the logs for the app(s) they own. This means your routing logic needs an access control check (e.g. based on the authenticated user's ID matching the app name or an internal mapping). Fortunately, if you've structured your platform as one Fly app per user, it's straightforward to maintain a mapping from user account to Fly app name and use that for authorization.
97
97
</div>
98
98
99
99
On startup the router opens one NATS connection with an org-scoped read-only token. When a developer signs in through your dashboard or CLI, the router authenticates that user, determines their Fly app name, and, if not already listening, subscribes to that app's subject. As log entries arrive, the router forwards them over a live channel—typically a websocket or Server-Sent Events stream—directly to the developer's browser or CLI.
@@ -104,6 +104,6 @@ The router itself is a Fly app that does the following:
104
104
- Wait for developers to request or connect for log streaming (e.g., a developer opens a web UI to view their app's live logs, or runs a command to view logs).
105
105
- When a request for a specific app's logs is received, subscribe to that app's log subject (if not already subscribed).
106
106
- Stream the incoming log messages to the requesting developer in real-time.
107
-
- Ensure that each developer only receives their own app's logs. The router should use the mapping of app <-> user to publish the right data to the correct output channel (and not mix different users' data).
107
+
- Ensure that each developer only receives their own app's logs. The router should use the mapping of app ← → user to publish the right data to the correct output channel (and not mix different users' data).
108
108
109
-
The approach above uses one NATS subscription _per user app_ for clarity. The messages are forwarded verbatim to the user's websocket in this case (as JSON strings), but you could transform them (for example, format them nicely or filter out certain internal logs) before sending. On the client side, you would simply read from the websocket or SSE stream and append new log lines to a console view.
109
+
This approach uses one NATS subscription _per user app_. The messages are forwarded verbatim to the user's websocket in this case (as JSON strings), but you could transform them (for example, format them nicely or filter out certain internal logs) before sending. On the client side, you would simply read from the websocket or SSE stream and append new log lines to a console view.
0 commit comments