Deno Runtime Logging Integration
Use the LogTide JavaScript SDK with Deno via npm specifiers for structured logging with secure-by-default permissions.
Deno supports npm packages via npm: specifiers, making the LogTide JavaScript SDK work directly. This guide covers setup, Fresh framework integration, Deno.serve patterns, and Deno Deploy considerations.
Why use LogTide with Deno?
- npm: specifier: Import
@logtide/nodedirectly — no import maps needed - Secure-by-default: Deno’s permission model means logging requires explicit
--allow-net - Native TypeScript: No build step, full type checking out of the box
- Deno Deploy: Ship logs from edge functions to your LogTide instance
- Standard APIs: Uses Web Standard
Request/Responsepatterns
Prerequisites
- Deno 1.38+ (2.x recommended for improved npm compatibility)
- LogTide instance with a DSN or API key
Quick Start
// main.ts
import { LogTideClient } from 'npm:@logtide/node';
const client = new LogTideClient({
dsn: Deno.env.get('LOGTIDE_DSN')!,
service: 'deno-app',
environment: Deno.env.get('DENO_ENV') ?? 'development',
});
client.info('Application started', { runtime: 'deno', version: Deno.version.deno });
Deno.serve({ port: 8000 }, async (req) => {
const url = new URL(req.url);
client.info(`${req.method} ${url.pathname}`);
return new Response('OK');
});
Run with permissions:
deno run --allow-net --allow-env main.ts
Environment Variables
Create a .env file and load it:
# .env
LOGTIDE_DSN=http://[email protected]:8080
DENO_ENV=development
deno run --allow-net --allow-env --allow-read=.env main.ts
Or with Deno 2.x, .env files load automatically with --allow-env.
Deno.serve with Structured Logging
// main.ts
import { LogTideClient } from 'npm:@logtide/node';
const client = new LogTideClient({
dsn: Deno.env.get('LOGTIDE_DSN')!,
service: 'api',
});
Deno.serve({ port: 8000 }, async (req) => {
const url = new URL(req.url);
const start = performance.now();
const traceId = req.headers.get('x-trace-id') ?? crypto.randomUUID();
// Skip health checks
if (url.pathname === '/health') return new Response('OK');
try {
const response = await handleRequest(req, url);
const durationMs = Math.round(performance.now() - start);
client.info(`${req.method} ${url.pathname} ${response.status}`, {
method: req.method,
path: url.pathname,
statusCode: response.status,
durationMs,
traceId,
});
response.headers.set('X-Trace-Id', traceId);
return response;
} catch (error) {
client.error(`${req.method} ${url.pathname} 500`, {
method: req.method,
path: url.pathname,
statusCode: 500,
traceId,
error: error instanceof Error ? error.message : String(error),
});
return new Response('Internal Server Error', { status: 500 });
}
});
async function handleRequest(req: Request, url: URL): Promise<Response> {
switch (url.pathname) {
case '/api/users':
return Response.json([]);
default:
return new Response('Not Found', { status: 404 });
}
}
Fresh Framework Integration
Fresh is Deno’s full-stack framework. Add logging to middleware and routes:
Middleware
// routes/_middleware.ts
import { FreshContext } from '$fresh/server.ts';
import { LogTideClient } from 'npm:@logtide/node';
const client = new LogTideClient({
dsn: Deno.env.get('LOGTIDE_DSN')!,
service: 'fresh-app',
});
export async function handler(req: Request, ctx: FreshContext) {
const url = new URL(req.url);
const start = performance.now();
const traceId = crypto.randomUUID();
// Pass trace ID to downstream handlers
ctx.state.traceId = traceId;
ctx.state.logtide = client;
const response = await ctx.next();
const durationMs = Math.round(performance.now() - start);
// Skip static assets
if (!url.pathname.startsWith('/_frsh/')) {
client.info(`${req.method} ${url.pathname} ${response.status}`, {
method: req.method,
path: url.pathname,
statusCode: response.status,
durationMs,
traceId,
});
}
response.headers.set('X-Trace-Id', traceId);
return response;
}
API Routes
// routes/api/users/[id].ts
import { Handlers } from '$fresh/server.ts';
export const handler: Handlers = {
async GET(_req, ctx) {
const { logtide, traceId } = ctx.state;
const { id } = ctx.params;
logtide.info('Fetching user', { userId: id, traceId });
const user = await db.getUser(id);
if (!user) {
logtide.warning('User not found', { userId: id, traceId });
return new Response('Not Found', { status: 404 });
}
return Response.json(user);
},
};
Islands (Client Components)
Islands run in the browser — don’t import server logging there. Keep logging in routes and middleware only.
Oak Framework Integration
If using Oak (Deno’s Express-like framework):
// main.ts
import { Application, Router } from 'https://deno.land/x/oak/mod.ts';
import { LogTideClient } from 'npm:@logtide/node';
const client = new LogTideClient({
dsn: Deno.env.get('LOGTIDE_DSN')!,
service: 'oak-api',
});
const app = new Application();
// Logging middleware
app.use(async (ctx, next) => {
const start = performance.now();
await next();
const durationMs = Math.round(performance.now() - start);
client.info(`${ctx.request.method} ${ctx.request.url.pathname} ${ctx.response.status}`, {
method: ctx.request.method,
path: ctx.request.url.pathname,
statusCode: ctx.response.status,
durationMs,
});
});
// Error handler
app.use(async (ctx, next) => {
try {
await next();
} catch (error) {
client.error('Unhandled error', {
error: error instanceof Error ? error.message : String(error),
path: ctx.request.url.pathname,
});
ctx.response.status = 500;
ctx.response.body = { error: 'Internal Server Error' };
}
});
const router = new Router();
router.get('/users/:id', (ctx) => {
client.info('Fetching user', { userId: ctx.params.id });
ctx.response.body = { id: ctx.params.id };
});
app.use(router.routes());
app.use(router.allowedMethods());
await app.listen({ port: 8000 });
Deno Deploy
Deno Deploy runs your code at the edge. LogTide works there with some considerations:
// main.ts (for Deno Deploy)
import { LogTideClient } from 'npm:@logtide/node';
const client = new LogTideClient({
dsn: Deno.env.get('LOGTIDE_DSN')!,
service: 'edge-api',
// Smaller batches for edge (shorter-lived processes)
batchSize: 10,
flushInterval: 2000,
});
Deno.serve(async (req) => {
const url = new URL(req.url);
const start = performance.now();
const response = await handleRequest(req, url);
const durationMs = Math.round(performance.now() - start);
client.info(`${req.method} ${url.pathname} ${response.status}`, {
method: req.method,
path: url.pathname,
statusCode: response.status,
durationMs,
region: Deno.env.get('DENO_REGION') ?? 'unknown',
});
return response;
});
Notes for Deploy:
- Set
LOGTIDE_DSNin the Deno Deploy dashboard environment variables - Use smaller batch sizes since edge functions may terminate quickly
- Network permissions are granted automatically on Deploy
Permissions Reference
Deno requires explicit permissions. For LogTide:
# Minimum permissions
deno run \
--allow-net=your-logtide-host:8080 \ # Network to LogTide
--allow-env=LOGTIDE_DSN,DENO_ENV \ # Environment variables
main.ts
# Development (more permissive)
deno run --allow-net --allow-env --allow-read main.ts
Docker Deployment
FROM denoland/deno:2.0.0
WORKDIR /app
# Cache dependencies
COPY deno.json deno.lock ./
RUN deno install
# Copy application
COPY . .
# Cache the main module
RUN deno cache main.ts
ENV LOGTIDE_DSN=""
EXPOSE 8000
CMD ["deno", "run", "--allow-net", "--allow-env", "main.ts"]
Performance
| Metric | Value |
|---|---|
| Startup time | ~100ms |
| Log call overhead | <0.3ms (batched) |
| Memory overhead | ~8MB |
| npm: specifier load | First run only (cached after) |
Troubleshooting
”Requires net access”
Run with --allow-net or specify your LogTide host:
deno run --allow-net=api.logtide.dev main.ts
npm package not found
Ensure you’re using the npm: prefix:
// Correct
import { LogTideClient } from 'npm:@logtide/node';
// Wrong (won't resolve)
import { LogTideClient } from '@logtide/node';
Slow first run
Deno downloads and caches npm packages on first run. Subsequent runs are fast. In Docker, use RUN deno cache main.ts to pre-cache.
Next Steps
- Node.js SDK Reference - Full SDK documentation
- Docker Integration - Container deployments
- Bun Integration - Alternative JS runtime