Dynamic Tags
import { Aside } from ‘@astrojs/starlight/components’;
Tags are the most powerful filtering mechanism in gunsole. They’re simple key-value pairs attached to log entries, but the magic is in how they surface in the UI.
How it works
Section titled “How it works”- You send a log with tags
- The desktop app extracts each key-value pair
- New keys appear as filter dropdowns in the filter bar
- New values appear as options in those dropdowns
- Value counts are shown so you know the distribution
No schema. No config file. No “register your tags” step. Just send them.
Example
Section titled “Example”gun.info({ bucket: "api", message: "Request handled", tags: { route: "/users", method: "GET", status: "200", },});
gun.info({ bucket: "api", message: "Request handled", tags: { route: "/orders", method: "POST", status: "201", },});
gun.error({ bucket: "api", message: "Request failed", tags: { route: "/orders", method: "POST", status: "500", },});After these three logs, the filter bar shows:
- route dropdown:
/users(1),/orders(2) - method dropdown:
GET(1),POST(2) - status dropdown:
200(1),201(1),500(1)
Select status: 500 to see only the failed request. Select route: /orders + method: POST to see all POST requests to /orders.
Tags vs. context
Section titled “Tags vs. context”Both tags and context accept arbitrary data, but they serve different purposes:
| Tags | Context | |
|---|---|---|
| Type | Record<string, string> (strings only) | Record<string, unknown> (any JSON) |
| Purpose | Filtering and grouping | Detailed inspection |
| UI | Appear as filter dropdowns | Shown in expanded log view |
| Indexed | Yes (fast queries) | No (stored as JSON blob) |
Rule of thumb: If you want to filter by it, use a tag. If you want to inspect it when looking at a specific log, use context.
gun.info({ bucket: "api", message: "POST /orders → 201", // Things you filter by tags: { route: "/orders", method: "POST", status: "201", }, // Things you look at when investigating context: { orderId: "ord_abc123", items: 3, total: 149.99, userId: "u_456", latencyMs: 234, },});Default tags
Section titled “Default tags”Set defaultTags in your client config to automatically attach tags to every log:
const gun = createGunsoleClient({ projectId: "my-app", apiKey: "dev", mode: "local", defaultTags: { service: "api-server", region: "us-east-1", version: "1.4.2", },});Every log from this client will have service, region, and version tags. Per-log tags are merged on top — if there’s a conflict, the per-log value wins.
Good tag patterns
Section titled “Good tag patterns”| Tag | Example values | Use case |
|---|---|---|
route | /users, /orders | Filter by API endpoint |
method | GET, POST, PUT | Filter by HTTP method |
status | 200, 404, 500 | Filter by response status |
feature | auth, checkout, search | Filter by product area |
action | click, submit, navigate | Filter by user action type |
service | api, worker, scheduler | Filter by microservice |
env | production, staging, local | Filter by environment |
component | Header, Cart, Modal | Filter by React component |
Storage
Section titled “Storage”Tags are stored in a separate tags table with a many-to-many relationship to logs. This makes tag queries fast — they use indexed JOINs rather than scanning JSON blobs.