T
TanStack3mo ago
absent-sapphire

Middleware global logging examples

Hello! I was wondering if anybody has managed to produce reasonable logging for tanstack/start on the server? I cannot find any examples of logging request/response and the details of it. request is always undefined (data coming in) and response is mostly just the serverFN response if there is one.
import {
createMiddleware,
registerGlobalMiddleware,
} from "@tanstack/react-start";
import * as Sentry from "@sentry/tanstackstart-react";

registerGlobalMiddleware({
middleware: [
createMiddleware({ type: "function" }).server(
Sentry.sentryGlobalServerMiddlewareHandler()
),
createMiddleware({ type: 'function' }).server(
async ({ next, data, context }) => {
console.log('Request received:', data)
console.log('Context:', context)
const result = await next()
console.log('Response processed:', result)
return result
},
)
],
});
import {
createMiddleware,
registerGlobalMiddleware,
} from "@tanstack/react-start";
import * as Sentry from "@sentry/tanstackstart-react";

registerGlobalMiddleware({
middleware: [
createMiddleware({ type: "function" }).server(
Sentry.sentryGlobalServerMiddlewareHandler()
),
createMiddleware({ type: 'function' }).server(
async ({ next, data, context }) => {
console.log('Request received:', data)
console.log('Context:', context)
const result = await next()
console.log('Response processed:', result)
return result
},
)
],
});
This is my middleware, but this doesn't really give me proper server logs and looking at the response of result it seems to be a lot of stuff we don't need. I couldn't find any examples of just ending up with json logs like:
req: {
"id": 1,
"method": "GET",
"url": "/",
"headers": {
"host": "localhost:3000",
"user-agent": "curl/7.43.0",
"accept": "*/*"
},
"remoteAddress": "::1",
"remotePort": 64386
}
req: {
"id": 1,
"method": "GET",
"url": "/",
"headers": {
"host": "localhost:3000",
"user-agent": "curl/7.43.0",
"accept": "*/*"
},
"remoteAddress": "::1",
"remotePort": 64386
}
Or how to construct them based on the fact I don't seem to have anything coming in for the request. Has anybody managed to do something with this?
1 Reply
ambitious-aqua
ambitious-aqua3mo ago
Hey! Been looking around for a while for this too and apparently there seems to be no way of doing this. I love having request logs in nextjs so would be awesome to have them here too Found a solution, a bit hacky but better than nothing. Only shows requests that the server handles, not client-side navigation. Just add this to your vite.config.ts
const config = defineConfig({
plugins: [
{
name: 'log-requests-with-host',
configureServer(server) {
server.middlewares.use((req, res, next) => {
const url = req.url ?? ''
const host = req.headers.host || 'unknown-host'
const startTime = Date.now()

// Skip Vite internals and assets
if (
url.startsWith('/@vite/') ||
url.startsWith('/@react-refresh') ||
url.startsWith('/~start/') ||
url.includes('.vite/deps/') ||
url.endsWith('.js?v=') ||
url.startsWith('/node_modules/') ||
url === '/favicon.ico' ||
url.endsWith('.css') ||
url.endsWith('.css?url') ||
url.startsWith('/src/') ||
url.includes('.ts') ||
url.includes('.tsx') ||
url.includes('.js') ||
url.includes('.jsx') ||
url.includes('.map')
) {
return next()
}

// Track response time
res.on('finish', () => {
const duration = Date.now() - startTime
if (duration >= 1000) {
const durationInSeconds = (duration / 1000).toFixed(3)
console.log(
`[${host}] ${req.method} ${url} in ${durationInSeconds}s`,
)
} else {
console.log(`[${host}] ${req.method} ${url} in ${duration}ms`)
}
})

next()
})
},
},
],
})
const config = defineConfig({
plugins: [
{
name: 'log-requests-with-host',
configureServer(server) {
server.middlewares.use((req, res, next) => {
const url = req.url ?? ''
const host = req.headers.host || 'unknown-host'
const startTime = Date.now()

// Skip Vite internals and assets
if (
url.startsWith('/@vite/') ||
url.startsWith('/@react-refresh') ||
url.startsWith('/~start/') ||
url.includes('.vite/deps/') ||
url.endsWith('.js?v=') ||
url.startsWith('/node_modules/') ||
url === '/favicon.ico' ||
url.endsWith('.css') ||
url.endsWith('.css?url') ||
url.startsWith('/src/') ||
url.includes('.ts') ||
url.includes('.tsx') ||
url.includes('.js') ||
url.includes('.jsx') ||
url.includes('.map')
) {
return next()
}

// Track response time
res.on('finish', () => {
const duration = Date.now() - startTime
if (duration >= 1000) {
const durationInSeconds = (duration / 1000).toFixed(3)
console.log(
`[${host}] ${req.method} ${url} in ${durationInSeconds}s`,
)
} else {
console.log(`[${host}] ${req.method} ${url} in ${duration}ms`)
}
})

next()
})
},
},
],
})

Did you find this page helpful?