Tips & Tricks
import { Aside } from ‘@astrojs/starlight/components’;
SDK patterns
Section titled “SDK patterns”Environment-aware initialization
Section titled “Environment-aware initialization”const gun = createGunsoleClient({ projectId: "my-app", apiKey: process.env.GUNSOLE_API_KEY || "dev", mode: process.env.NODE_ENV === "production" ? "cloud" : "local", env: process.env.NODE_ENV, appVersion: process.env.npm_package_version, defaultTags: { buildId: process.env.BUILD_ID, commit: process.env.GIT_SHA?.slice(0, 7), },});Request-scoped logging
Section titled “Request-scoped logging”Create a per-request logger that automatically carries the trace ID and user:
function createRequestLogger(req) { const traceId = req.headers["x-request-id"] || crypto.randomUUID();
return { info: (bucket, message, extra = {}) => gun.info({ bucket, message, traceId, ...extra }), error: (bucket, message, extra = {}) => gun.error({ bucket, message, traceId, ...extra }), warn: (bucket, message, extra = {}) => gun.warn({ bucket, message, traceId, ...extra }), debug: (bucket, message, extra = {}) => gun.debug({ bucket, message, traceId, ...extra }), };}
app.use((req, res, next) => { req.log = createRequestLogger(req); next();});
// In route handlersapp.get("/users", (req, res) => { req.log.info("api", "Fetching users"); // ...});Timing helper
Section titled “Timing helper”function timed(gun, bucket, message, fn) { const start = Date.now(); const result = fn();
if (result instanceof Promise) { return result.then((val) => { gun.debug({ bucket, message: `${message} (${Date.now() - start}ms)`, context: { durationMs: Date.now() - start }, tags: { timed: "true" }, }); return val; }); }
gun.debug({ bucket, message: `${message} (${Date.now() - start}ms)`, context: { durationMs: Date.now() - start }, tags: { timed: "true" }, }); return result;}
// Usageconst users = await timed(gun, "db", "Fetch all users", () => db.query("SELECT * FROM users"));Desktop app patterns
Section titled “Desktop app patterns”Saved filter recipes
Section titled “Saved filter recipes”Some useful filter combinations to save:
| Name | Config |
|---|---|
| Errors only | Level: error only |
| Slow queries | Bucket: db, search: “slow” or tag timed: true |
| Auth issues | Bucket: auth, level: warn + error |
| Last 5 min | Time range: 5m preset, all levels |
| Specific user | Tag filter on user-related tags |
Keyboard shortcuts
Section titled “Keyboard shortcuts”| Shortcut | Action |
|---|---|
Cmd+, / Ctrl+, | Open settings |
Cmd+N / Ctrl+N | New window |
Multi-window workflow
Section titled “Multi-window workflow”Open the same project in multiple windows with different filters. One window for errors, another for the full firehose. Each window maintains its own filter state.
Log hygiene
Section titled “Log hygiene”Don’t over-log
Section titled “Don’t over-log”// Bad — this will flood your viewerapp.use((req, res, next) => { gun.debug({ bucket: "http", message: `Headers: ${JSON.stringify(req.headers)}` }); gun.debug({ bucket: "http", message: `Body: ${JSON.stringify(req.body)}` }); gun.debug({ bucket: "http", message: `Query: ${JSON.stringify(req.query)}` }); next();});
// Good — one log with contextapp.use((req, res, next) => { gun.debug({ bucket: "http", message: `${req.method} ${req.path}`, context: { headers: req.headers, body: req.body, query: req.query }, }); next();});Use buckets, not prefixes
Section titled “Use buckets, not prefixes”// Badgun.info({ bucket: "general", message: "[API] Request received" });gun.info({ bucket: "general", message: "[DB] Query executed" });
// Goodgun.info({ bucket: "api", message: "Request received" });gun.info({ bucket: "db", message: "Query executed" });Tags are for filtering, context is for inspection
Section titled “Tags are for filtering, context is for inspection”// Bad — high-cardinality taggun.info({ bucket: "api", message: "Request", tags: { userId: "u_12345", orderId: "ord_67890" },});
// Good — IDs in context, categories in tagsgun.info({ bucket: "api", message: "Request", tags: { route: "/orders", method: "POST" }, context: { userId: "u_12345", orderId: "ord_67890" },});Scripting with the API
Section titled “Scripting with the API”Pipe logs to a file
Section titled “Pipe logs to a file”curl -s "http://localhost:17655/api/logs?projectId=my-app&level=error&limit=1000" | jq '.logs[] | .message'Watch for errors
Section titled “Watch for errors”while true; do curl -s "http://localhost:17655/api/logs/tail?level=error&limit=5" | jq '.logs[] | "\(.timestamp) \(.message)"' sleep 2doneSend a log from any language
Section titled “Send a log from any language”The protocol is just POST /logs with JSON. If there’s no SDK for your language, it takes about 10 lines of code to send a log. See the REST API docs for the exact format.