<commit_before>// Copyright 2015 The LUCI Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

package middleware

import (
	"net/http"

	log "github.com/luci/luci-go/common/logging"
	"github.com/luci/luci-go/common/runtime/paniccatcher"
	"github.com/luci/luci-go/server/router"
)

// WithPanicCatcher is a middleware that catches panics, dumps stack trace to
// logging and returns HTTP 500.
func WithPanicCatcher(c *router.Context, next router.Handler) {
	ctx := c.Context
	w := c.Writer
	req := c.Request
	defer paniccatcher.Catch(func(p *paniccatcher.Panic) {
		log.Fields{
			"panic.error": p.Reason,
		}.Errorf(ctx, "Caught panic during handling of %q:\n%s", req.RequestURI, p.Stack)

		// Note: it may be too late to send HTTP 500 if `next` already sent
		// headers. But there's nothing else we can do at this point anyway.
		http.Error(w, "Internal Server Error. See logs.", http.StatusInternalServerError)
	})
	next(c)
}
<commit_msg>paniccatcher: log reason before the stack<commit_after>// Copyright 2015 The LUCI Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

package middleware

import (
	"net/http"

	log "github.com/luci/luci-go/common/logging"
	"github.com/luci/luci-go/common/runtime/paniccatcher"
	"github.com/luci/luci-go/server/router"
)

// WithPanicCatcher is a middleware that catches panics, dumps stack trace to
// logging and returns HTTP 500.
func WithPanicCatcher(c *router.Context, next router.Handler) {
	ctx := c.Context
	w := c.Writer
	req := c.Request
	defer paniccatcher.Catch(func(p *paniccatcher.Panic) {
		// Log the reason before the stack in case appengine cuts entire log
		// message due to size limitations.
		log.Fields{
			"panic.error": p.Reason,
		}.Errorf(ctx, "Caught panic during handling of %q: %s\n%s", req.RequestURI, p.Reason, p.Stack)

		// Note: it may be too late to send HTTP 500 if `next` already sent
		// headers. But there's nothing else we can do at this point anyway.
		http.Error(w, "Internal Server Error. See logs.", http.StatusInternalServerError)
	})
	next(c)
}

{'fraction_non_alphanumeric': 0.11255605381165919, 'fraction_numerical': 0.010762331838565023, 'mean_word_length': 3.7569296375266523, 'pattern_counts': {'":': 2, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4020264', 'n_tokens_mistral': 777, 'n_tokens_neox': 724, 'n_words': 252}