# Event Reporting

This page explains how to report application events to the scoring engine with `LoginFailure` and `NotFound404`, and the side effects of both calls.

## Two Reporting Methods

| Method | Key incremented | Effect on scoring |
|---|---|---|
| `LoginFailure(w, r)` | `login:failure:{sid}` | Adds `ScoreLoginFailure` once the count exceeds `LoginFailure` (4) |
| `NotFound404(w, r)` | `notfound:404:{sid}` | Adds `ScoreNotFound404` once the count exceeds `NotFound404` (8) |

Both counters are per session; the first increment sets a one-hour expiry that is never extended afterward (a fixed window). Scoring rules are in [Correlation Signals](/correlation-signals).

## Login Failures

```go
func loginHandler(sentry *golangIPSentry.IPGuardian) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		if !validCredential(r) {
			if err := sentry.LoginFailure(w, r); err != nil {
				log.Printf("report login failure: %v", err)
			}
			http.Error(w, "Unauthorized", http.StatusUnauthorized)
			return
		}
		w.Write([]byte("welcome"))
	}
}
```

## 404 Scans

```go
r := gin.New()
r.Use(gin.Recovery(), sentry.GinMiddleware())
r.NoRoute(func(c *gin.Context) {
	if err := sentry.NotFound404(c.Writer, c.Request); err != nil {
		log.Printf("report 404: %v", err)
	}
	c.JSON(http.StatusNotFound, gin.H{"error": "not found"})
})
```

## Side Effects

Both methods run device identification again internally:

| Side effect | Impact |
|---|---|
| `frequency:{ip}:{minute}` increments again | The same request counts twice toward the per-minute limit |
| Both `Set-Cookie` headers are rewritten | Call before the handler writes a body |
| Request without cookies | The count lands on the session issued in this response; it only matters if the client keeps that cookie |

## Reach

With defaults, 7 login failures add only 30 points and never cause a rejection on their own; to make brute force hit the limit directly, lower `LoginFailure` or raise `ScoreLoginFailure`, see [Parameters](/parameters). An attacker who drops cookies moves to a new session, so IP-level signals such as `ip:device` have to carry the load.
