LogstackLogstack

Framework Integrations

Integrate Logstack with Express, Next.js, NestJS, Django, FastAPI, Go net/http, and more.

Framework integrations

Guides for popular stacks. JavaScript examples use logstack-js; Python uses logstack-py; Go uses logstack-go-sdk.

RuntimePackageFull docs
Node / browserlogstack-jsJavaScript SDK
Gologstack-go-sdkGo SDK
Pythonlogstack-pyPython SDK

JavaScript frameworks

Express.js

Full integration with request logging and error handling.

src/lib/logger.ts
import { createLogStack } from "logstack-js";
 
export const logstack = createLogStack({
  apiKey: process.env.LOGSTACK_API_KEY!,
});
src/middleware/logging.ts
import { Request, Response, NextFunction } from "express";
import { logstack } from "../lib/logger";
 
export function requestLogger(req: Request, res: Response, next: NextFunction) {
  const start = Date.now();
 
  res.on("finish", () => {
    const duration = Date.now() - start;
    const level =
      res.statusCode >= 500 ? "error" : res.statusCode >= 400 ? "warn" : "info";
 
    logstack.log({
      level,
      message: `${req.method} ${req.path}`,
      source: "http",
      metadata: {
        method: req.method,
        path: req.path,
        statusCode: res.statusCode,
        duration,
        userAgent: req.get("user-agent"),
        ip: req.ip,
      },
    });
  });
 
  next();
}
src/middleware/error.ts
import { Request, Response, NextFunction } from "express";
import { logstack } from "../lib/logger";
 
export function errorHandler(
  err: Error,
  req: Request,
  res: Response,
  next: NextFunction,
) {
  logstack.error("Unhandled error", {
    error: err.message,
    stack: err.stack,
    path: req.path,
    method: req.method,
  });
 
  res.status(500).json({ error: "Internal server error" });
}
src/app.ts
import express from "express";
import { requestLogger } from "./middleware/logging";
import { errorHandler } from "./middleware/error";
import { logstack } from "./lib/logger";
 
const app = express();
 
app.use(requestLogger);
 
// Your routes here
app.get("/health", (req, res) => res.json({ status: "ok" }));
 
app.use(errorHandler);
 
// Graceful shutdown
process.on("SIGTERM", async () => {
  await logstack.close();
  process.exit(0);
});
 
app.listen(3000);

Next.js (App Router)

src/lib/logger.ts
import { createLogStack } from 'logstack-js';
 
// Create singleton instance
export const logstack = createLogStack({
apiKey: process.env.LOGSTACK_API_KEY!,
});
src/app/users/page.tsx
import { logstack } from '@/lib/logger';
 
export default async function UsersPage() {
  logstack.info('Users page viewed');
 
  const users = await fetchUsers();
 
  return <UserList users={users} />;
}

Fastify

src/plugins/logger.ts
import { FastifyPluginAsync } from "fastify";
import fp from "fastify-plugin";
import { createLogStack } from "logstack-js";
 
const logstack = createLogStack({
  apiKey: process.env.LOGSTACK_API_KEY!,
});
 
const loggerPlugin: FastifyPluginAsync = async (fastify) => {
  // Decorate fastify with logstack
  fastify.decorate("logstack", logstack);
 
  // Request logging hook
  fastify.addHook("onResponse", async (request, reply) => {
    const level =
      reply.statusCode >= 500
        ? "error"
        : reply.statusCode >= 400
          ? "warn"
          : "info";
 
    logstack.log({
      level,
      message: `${request.method} ${request.url}`,
      source: "http",
      metadata: {
        method: request.method,
        url: request.url,
        statusCode: reply.statusCode,
        duration: reply.elapsedTime,
        ip: request.ip,
      },
    });
  });
 
  // Graceful shutdown
  fastify.addHook("onClose", async () => {
    await logstack.close();
  });
};
 
export default fp(loggerPlugin);
src/app.ts
import Fastify from "fastify";
import loggerPlugin from "./plugins/logger";
 
const app = Fastify();
 
app.register(loggerPlugin);
 
app.get("/health", async () => ({ status: "ok" }));
 
app.listen({ port: 3000 });

NestJS

src/common/logger/logstack.service.ts
import { Injectable, OnModuleDestroy } from "@nestjs/common";
import { createLogStack, LogStackClient } from "logstack-js";
 
@Injectable()
export class LogStackService implements OnModuleDestroy {
  private client: LogStackClient;
 
  constructor() {
    this.client = createLogStack({
      apiKey: process.env.LOGSTACK_API_KEY!,
    });
  }
 
  info(message: string, metadata?: Record<string, any>) {
    this.client.info(message, metadata);
  }
 
  warn(message: string, metadata?: Record<string, any>) {
    this.client.warn(message, metadata);
  }
 
  error(message: string, metadata?: Record<string, any>) {
    this.client.error(message, metadata);
  }
 
  critical(message: string, metadata?: Record<string, any>) {
    this.client.critical(message, metadata);
  }
 
  async onModuleDestroy() {
    await this.client.close();
  }
}
src/common/interceptors/logging.interceptor.ts
import {
  Injectable,
  NestInterceptor,
  ExecutionContext,
  CallHandler,
} from "@nestjs/common";
import { Observable } from "rxjs";
import { tap } from "rxjs/operators";
import { LogStackService } from "../logger/logstack.service";
 
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
  constructor(private logstack: LogStackService) {}
 
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const request = context.switchToHttp().getRequest();
    const start = Date.now();
 
    return next.handle().pipe(
      tap({
        next: () => {
          this.logstack.info(`${request.method} ${request.url}`, {
            duration: Date.now() - start,
            statusCode: context.switchToHttp().getResponse().statusCode,
          });
        },
        error: (error) => {
          this.logstack.error(`${request.method} ${request.url}`, {
            duration: Date.now() - start,
            error: error.message,
          });
        },
      }),
    );
  }
}

Register LogStackService as a global provider and LoggingInterceptor as a global interceptor in your AppModule.

Hono

src/index.ts
import { Hono } from "hono";
import { createLogStack } from "logstack-js";
 
const app = new Hono();
const logstack = createLogStack({
  apiKey: process.env.LOGSTACK_API_KEY!,
});
 
// Logging middleware
app.use("*", async (c, next) => {
  const start = Date.now();
  await next();
 
  const level =
    c.res.status >= 500 ? "error" : c.res.status >= 400 ? "warn" : "info";
 
  logstack.log({
    level,
    message: `${c.req.method} ${c.req.path}`,
    source: "http",
    metadata: {
      method: c.req.method,
      path: c.req.path,
      status: c.res.status,
      duration: Date.now() - start,
    },
  });
});
 
app.get("/", (c) => c.json({ message: "Hello!" }));
 
export default app;

Python frameworks

Django

pip install "logstack-py[django]"
settings.py
import os
from logstack import LogStackClient
 
LOGSTACK_CLIENT = LogStackClient(
    api_key=os.environ["LOGSTACK_API_KEY"],
    environment=os.environ.get("ENVIRONMENT", "production"),
)
 
MIDDLEWARE = [
    # …
    "logstack.middleware.DjangoMiddleware",
    # …
]

DjangoMiddleware captures unhandled exceptions (path, method, user, IP, traceback). Use the client for business events:

from django.conf import settings
 
settings.LOGSTACK_CLIENT.info("checkout completed", metadata={"orderId": order.id})

Full details: Python SDK — Django.

FastAPI

pip install "logstack-py[fastapi]"
main.py
from fastapi import FastAPI
from logstack import LogStackClient, create_fastapi_middleware
 
app = FastAPI()
client = LogStackClient(api_key="ls_live_xxx", environment="production")
app.add_middleware(create_fastapi_middleware(client))
 
@app.get("/health")
def health():
    client.info("health check")
    return {"ok": True}
 
@app.on_event("shutdown")
def shutdown():
    client.close()

Full details: Python SDK — FastAPI.

Go services

main.go
package main
 
import (
	"net/http"
	"os"
	"time"
 
	logstack "github.com/mosesedem/logstack/packages/logstack-go-sdk"
)
 
func main() {
	client := logstack.NewClient(logstack.Config{
		APIKey:      os.Getenv("LOGSTACK_API_KEY"),
		Environment: "production",
	})
	defer client.Close()
 
	mux := http.NewServeMux()
	mux.HandleFunc("/api/", func(w http.ResponseWriter, r *http.Request) {
		start := time.Now()
		// … handle request …
		w.WriteHeader(http.StatusOK)
 
		_ = client.Info(r.Context(), r.Method+" "+r.URL.Path, map[string]interface{}{
			"status":   200,
			"duration": time.Since(start).Milliseconds(),
		})
	})
 
	_ = http.ListenAndServe(":8080", mux)
}

With default CaptureStdLog, existing log.Printf calls are shipped as source: "go-log". See Go SDK.

On this page