Compare commits

..

4 Commits

Author SHA1 Message Date
agent-company 5d3ce5baf8 feat: add request-id and duration_ms to structured logging middleware
Enhance the logging middleware with a randomly generated request-id
(X-Request-ID header) for request tracing, duration in milliseconds
for easier metric aggregation, and user-agent for client identification.

Closes leeworks-agents/gitea-mobile#200

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-20 15:10:08 +00:00
AI-Manager baf829349c Merge pull request 'docs: fix SMOKE_TEST.md triage route (/triage -> /)' (#159) from fix/smoke-test-triage-route-157 into master
Build and Push / test (push) Failing after 1m35s
Build and Push / build (push) Has been skipped
2026-03-29 03:04:47 +00:00
agent-company 3145acc423 docs: fix SMOKE_TEST.md triage route reference (/triage -> /)
The triage queue is served at / (the dashboard), not a separate /triage
route. Update Step 7 and the expected results summary table to reference
the correct route, consistent with ROADMAP.md and handlers.go.

Closes leeworks-agents/gitea-mobile#157

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 03:04:07 +00:00
AI-Manager ce3fc36835 Merge pull request 'chore: add go vet step to CI workflow' (#156) from chore/add-go-vet-ci-154 into master
Build and Push / test (push) Failing after 14m51s
Build and Push / build (push) Has been cancelled
2026-03-29 01:03:01 +00:00
2 changed files with 25 additions and 5 deletions
+3 -3
View File
@@ -73,9 +73,9 @@ curl -s https://gitea-mobile.testing.leeworks.dev | head -5
3. Tap on a PR to see details 3. Tap on a PR to see details
4. **Expected**: PR diff summary or review status displays correctly 4. **Expected**: PR diff summary or review status displays correctly
## Step 7: Core Functionality -- Triage Queue ## Step 7: Core Functionality -- Dashboard / Triage Queue
1. Navigate to the Triage tab (`/triage`) 1. Navigate to the Dashboard/Triage tab (`/`)
2. **Expected**: Unassigned issues and PRs awaiting review appear sorted by priority 2. **Expected**: Unassigned issues and PRs awaiting review appear sorted by priority
## Step 8: Create Issue (Write Operation) ## Step 8: Create Issue (Write Operation)
@@ -116,7 +116,7 @@ curl -s https://gitea-mobile.testing.leeworks.dev | head -5
| 4 | Auth | Token saved, API calls work | | 4 | Auth | Token saved, API calls work |
| 5 | Issues | List loads, filter works | | 5 | Issues | List loads, filter works |
| 6 | PRs | List loads with review status | | 6 | PRs | List loads with review status |
| 7 | Triage | Queue displays correctly | | 7 | Dashboard/Triage | Queue displays correctly at `/` |
| 8 | Create issue | Issue created in Gitea | | 8 | Create issue | Issue created in Gitea |
| 9 | Apply label | Label applied via API | | 9 | Apply label | Label applied via API |
| 10 | PWA | Standalone mode, safe areas, dark mode | | 10 | PWA | Standalone mode, safe areas, dark mode |
+22 -2
View File
@@ -1,6 +1,8 @@
package middleware package middleware
import ( import (
"crypto/rand"
"encoding/hex"
"log/slog" "log/slog"
"net/http" "net/http"
"time" "time"
@@ -17,21 +19,39 @@ func (rw *responseWriter) WriteHeader(code int) {
rw.ResponseWriter.WriteHeader(code) rw.ResponseWriter.WriteHeader(code)
} }
// Logging returns middleware that logs each HTTP request with structured logging. // generateRequestID creates a short random hex string for request tracing.
func generateRequestID() string {
b := make([]byte, 8)
if _, err := rand.Read(b); err != nil {
return "unknown"
}
return hex.EncodeToString(b)
}
// Logging returns middleware that logs each HTTP request with structured fields:
// method, path, status, duration (ms), request-id, and remote address.
func Logging() func(http.Handler) http.Handler { func Logging() func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler { return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now() start := time.Now()
requestID := generateRequestID()
rw := &responseWriter{ResponseWriter: w, statusCode: http.StatusOK} rw := &responseWriter{ResponseWriter: w, statusCode: http.StatusOK}
// Set request ID header for downstream correlation.
w.Header().Set("X-Request-ID", requestID)
next.ServeHTTP(rw, r) next.ServeHTTP(rw, r)
duration := time.Since(start)
slog.Info("http request", slog.Info("http request",
"method", r.Method, "method", r.Method,
"path", r.URL.Path, "path", r.URL.Path,
"status", rw.statusCode, "status", rw.statusCode,
"duration", time.Since(start).String(), "duration_ms", duration.Milliseconds(),
"duration", duration.String(),
"request_id", requestID,
"remote", r.RemoteAddr, "remote", r.RemoteAddr,
"user_agent", r.UserAgent(),
) )
}) })
} }