2 Commits
Author SHA1 Message Date
sneak 96d8e7c1aa Name Sentry transactions after the route they matched (closes #185)
check / check (push) Successful in 14m13s
sentryhttp names each transaction after the concrete path, which the
BeforeSendTransaction hook has to withhold, so with tracing on every
transaction would land in one Sentry group, POST /(redacted). A
middleware installed beside every sentryhttp handler now renames the
transaction to the method and chi route pattern once the request is
routed, and sets its source to route. The hook keeps a route-sourced
name and withholds every other name as before, so a request that
matched no route still reads POST /(redacted). Tracing stays off.

Model: opus-5-5
2026-10-12 23:46:21 +00:00
clawbot 9199544999 Document that DATA_DIR must be on a local filesystem (closes #295)
check / check (push) Successful in 12m55s
SQLite in WAL mode maps each database's -shm file into memory, and
network filesystems do not support that reliably, so the README now
says DATA_DIR must be local and names NFS and SMB/CIFS as unsupported.
It also says what a disk I/O error with code 522 points at and what to
try first. ZFS is not called unsupported: the one failure seen there
was never reproduced.

Model: opus-5-5
2026-10-13 01:29:42 +02:00
2 changed files with 32 additions and 21 deletions

No files matched your search

+7
View File
@@ -941,6 +941,13 @@ with an error naming it: for `webhooker.db` the server and `webhooker resetpw`
stop, and an event or archive database fails as a damaged one does (see stop, and an event or archive database fails as a damaged one does (see
[Database Architecture](#database-architecture)). [Database Architecture](#database-architecture)).
**`DATA_DIR` must be on a local filesystem.** Under WAL, SQLite maps each
database's `-shm` file into memory, which network filesystems (NFS, SMB/CIFS) do
not support reliably, so they are not supported. webhooker does not check which
filesystem `DATA_DIR` is on. An error reading `disk I/O error (522)`
(`SQLITE_IOERR_SHORT_READ`) points at the storage under `DATA_DIR`, not at
locking; moving `DATA_DIR` to a plain local disk is the first thing to try.
Configuration is **not** in `DATA_DIR` — it comes from the environment and from Configuration is **not** in `DATA_DIR` — it comes from the environment and from
a `.env` file read out of the process working directory. Back that up with your a `.env` file read out of the process working directory. Back that up with your
deployment config, separately. deployment config, separately.
+25 -21
View File
@@ -1,6 +1,7 @@
package server package server
import ( import (
"context"
"net/http" "net/http"
"net/url" "net/url"
"strings" "strings"
@@ -157,36 +158,39 @@ func sentryRoutePattern(hint *sentry.EventHint) string {
// It has to run inside the sentryhttp handler, where the transaction // It has to run inside the sentryhttp handler, where the transaction
// is on the request context. It renames on the way out, once chi has // is on the request context. It renames on the way out, once chi has
// routed the request, and does so in a defer so that a request whose // routed the request, and does so in a defer so that a request whose
// handler panics is named too. A request that matched no route has no // handler panics is named too. The context is taken when the defer is
// pattern; its name is left as the SDK set it, for // set up, before routing, but the chi routing context on it is a
// scrubSentryRequest to withhold. // pointer that chi fills in as it routes.
func nameSentryTransaction(next http.Handler) http.Handler { func nameSentryTransaction(next http.Handler) http.Handler {
return http.HandlerFunc( return http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) { func(w http.ResponseWriter, r *http.Request) {
defer func() { defer setSentryTransactionName(r.Context(), r.Method)
transaction := sentry.TransactionFromContext(
r.Context(),
)
rctx := chi.RouteContext(r.Context())
if transaction == nil || rctx == nil {
return
}
pattern := rctx.RoutePattern()
if pattern == "" {
return
}
transaction.Name = r.Method + " " + pattern
transaction.Source = sentry.SourceRoute
}()
next.ServeHTTP(w, r) next.ServeHTTP(w, r)
}, },
) )
} }
// setSentryTransactionName does the rename for nameSentryTransaction.
// A request that matched no route has no pattern; its name is left as
// the SDK set it, for scrubSentryRequest to withhold.
func setSentryTransactionName(ctx context.Context, method string) {
transaction := sentry.TransactionFromContext(ctx)
rctx := chi.RouteContext(ctx)
if transaction == nil || rctx == nil {
return
}
pattern := rctx.RoutePattern()
if pattern == "" {
return
}
transaction.Name = method + " " + pattern
transaction.Source = sentry.SourceRoute
}
// sentryRouteURL rebuilds an event's request URL with the route // sentryRouteURL rebuilds an event's request URL with the route
// pattern in place of the concrete path. // pattern in place of the concrete path.
// //