Debugging logs
Send debugging information in an errored response to a logging service.
export default { async fetch(request, env, ctx) { // Service configured to receive logs const LOG_URL = "https://log-service.example.com/";
async function postLog(data) { return await fetch(LOG_URL, { method: "POST", body: data, }); }
let response;
try { response = await fetch(request); if (!response.ok && !response.redirected) { const body = await response.text(); throw new Error( "Bad response at origin. Status: " + response.status + " Body: " + // Ensure the string is small enough to be a header body.trim().substring(0, 10), ); } } catch (err) { // Without ctx.waitUntil(), your fetch() to Cloudflare's // logging service may or may not complete ctx.waitUntil(postLog(err.toString())); const stack = JSON.stringify(err.stack) || err; // Copy the response and initialize body to the stack trace response = new Response(stack, response); // Add the error stack into a header to find out what happened response.headers.set("X-Debug-stack", stack); response.headers.set("X-Debug-err", err); } return response; },};
interface Env {}export default { async fetch(request, env, ctx): Promise<Response> { // Service configured to receive logs const LOG_URL = "https://log-service.example.com/";
async function postLog(data) { return await fetch(LOG_URL, { method: "POST", body: data, }); }
let response;
try { response = await fetch(request); if (!response.ok && !response.redirected) { const body = await response.text(); throw new Error( "Bad response at origin. Status: " + response.status + " Body: " + // Ensure the string is small enough to be a header body.trim().substring(0, 10), ); } } catch (err) { // Without ctx.waitUntil(), your fetch() to Cloudflare's // logging service may or may not complete ctx.waitUntil(postLog(err.toString())); const stack = JSON.stringify(err.stack) || err; // Copy the response and initialize body to the stack trace response = new Response(stack, response); // Add the error stack into a header to find out what happened response.headers.set("X-Debug-stack", stack); response.headers.set("X-Debug-err", err); } return response; },} satisfies ExportedHandler<Env>;
import jsonimport tracebackfrom pyodide.ffi import create_once_callablefrom js import Response, fetch, Headers
async def on_fetch(request, _env, ctx): # Service configured to receive logs log_url = "https://log-service.example.com/"
async def post_log(data): return await fetch(log_url, method="POST", body=data)
response = await fetch(request)
try: if not response.ok and not response.redirected: body = await response.text() # Simulating an error. Ensure the string is small enough to be a header raise Exception(f'Bad response at origin. Status:{response.status} Body:{body.strip()[:10]}') except Exception as e: # Without ctx.waitUntil(), your fetch() to Cloudflare's # logging service may or may not complete ctx.waitUntil(create_once_callable(post_log(e))) stack = json.dumps(traceback.format_exc()) or e # Copy the response and add to header response = Response.new(stack, response) response.headers["X-Debug-stack"] = stack response.headers["X-Debug-err"] = e
return response
import { Hono } from 'hono';
// Define the environment with appropriate typesinterface Env {}
const app = new Hono<{ Bindings: Env }>();
// Service configured to receive logsconst LOG_URL = "https://log-service.example.com/";
// Function to post logs to an external serviceasync function postLog(data: string) { return await fetch(LOG_URL, { method: "POST", body: data, });}
// Middleware to handle error loggingapp.use('*', async (c, next) => { try { // Process the request with the next handler await next();
// After processing, check if the response indicates an error if (c.res && (!c.res.ok && !c.res.redirected)) { const body = await c.res.clone().text(); throw new Error( "Bad response at origin. Status: " + c.res.status + " Body: " + // Ensure the string is small enough to be a header body.trim().substring(0, 10) ); }
} catch (err) { // Without waitUntil, the fetch to the logging service may not complete c.executionCtx.waitUntil( postLog(err.toString()) );
// Get the error stack or error itself const stack = JSON.stringify(err.stack) || err.toString();
// Create a new response with the error information const response = c.res ? new Response(stack, { status: c.res.status, headers: c.res.headers }) : new Response(stack, { status: 500 });
// Add debug headers response.headers.set("X-Debug-stack", stack); response.headers.set("X-Debug-err", err.toString());
// Set the modified response c.res = response; }});
// Default route handler that passes requests throughapp.all('*', async (c) => { return fetch(c.req.raw);});
export default app;
Was this helpful?
- Resources
- API
- New to Cloudflare?
- Products
- Sponsorships
- Open Source
- Support
- Help Center
- System Status
- Compliance
- GDPR
- Company
- cloudflare.com
- Our team
- Careers
- 2025 Cloudflare, Inc.
- Privacy Policy
- Terms of Use
- Report Security Issues
- Trademark