feat: add responseWrapper to exclude errors (status codes >= 400) from being reported
This commit is contained in:
parent
02f9dd951c
commit
a978d4921d
4 changed files with 78 additions and 6 deletions
|
|
@ -86,6 +86,7 @@ entryPoints:
|
||||||
|---------------------|-------------|------------|-----------------------------------------------------------------------------------------------------------------------------------------------|
|
|---------------------|-------------|------------|-----------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `disabled` | false | `bool` | Set to `true` to disable the plugin |
|
| `disabled` | false | `bool` | Set to `true` to disable the plugin |
|
||||||
| `debug` | false | `bool` | Something doesn't work? Set to `true` to see more logs (plugins doesn't have access to Traefik's log level) |
|
| `debug` | false | `bool` | Something doesn't work? Set to `true` to see more logs (plugins doesn't have access to Traefik's log level) |
|
||||||
|
| `queueSize` | 1000 | `int` | The maximum number of events that can be queued before they are sent to the Umami server |
|
||||||
| `umamiHost` | - | `string` | Umami server url, reachable from within traefik (container), e.g. `http://umami:3000` |
|
| `umamiHost` | - | `string` | Umami server url, reachable from within traefik (container), e.g. `http://umami:3000` |
|
||||||
| `umamiToken` | - | `string` | An API Token, used to automatize work with websites, not needed if you provide `websites` |
|
| `umamiToken` | - | `string` | An API Token, used to automatize work with websites, not needed if you provide `websites` |
|
||||||
| `umamiUsername` | - | `string` | An alternative to `umamiToken`, you can provide an username and password |
|
| `umamiUsername` | - | `string` | An alternative to `umamiToken`, you can provide an username and password |
|
||||||
|
|
@ -93,6 +94,7 @@ entryPoints:
|
||||||
| `umamiTeamId` | - | `string` | In order to organize websites, you can use Umami Teams |
|
| `umamiTeamId` | - | `string` | In order to organize websites, you can use Umami Teams |
|
||||||
| `websites` | - | `map` | A map of hostnames and their associated Umami IDs. Can also be used to override or extend fetched websites |
|
| `websites` | - | `map` | A map of hostnames and their associated Umami IDs. Can also be used to override or extend fetched websites |
|
||||||
| `createNewWebsites` | false | `bool` | If set to `true`, will try to create a new website on Umami, if domain not found there |
|
| `createNewWebsites` | false | `bool` | If set to `true`, will try to create a new website on Umami, if domain not found there |
|
||||||
|
| `trackErrors` | false | `bool` | If set to `true`, will track errors (status codes >= 400) |
|
||||||
| `trackAllResources` | false | `bool` | Defines whether all requests for any resource should be tracked. By default, only requests that are believed to contain content are tracked |
|
| `trackAllResources` | false | `bool` | Defines whether all requests for any resource should be tracked. By default, only requests that are believed to contain content are tracked |
|
||||||
| `trackExtensions` | | `string[]` | Defines an alternative list of file extensions that should be tracked |
|
| `trackExtensions` | | `string[]` | Defines an alternative list of file extensions that should be tracked |
|
||||||
| `ignoreUserAgents` | | `string[]` | A list of user agents that should be ignored from tracking, e.g. `["Googlebot", "Uptime-Kuma"]` (matched with `strings.Contains`) |
|
| `ignoreUserAgents` | | `string[]` | A list of user agents that should be ignored from tracking, e.g. `["Googlebot", "Uptime-Kuma"]` (matched with `strings.Contains`) |
|
||||||
|
|
|
||||||
44
responsewriter.go
Normal file
44
responsewriter.go
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
package traefik_umami_feeder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Copied and adapted from https://github.com/safing/plausiblefeeder/blob/master/responsewriter.go
|
||||||
|
// Licensed as MIT license
|
||||||
|
|
||||||
|
// ResponseWriter is used to wrap given response writers.
|
||||||
|
type ResponseWriter struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
|
||||||
|
request *http.Request
|
||||||
|
feeder *UmamiFeeder
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteHeader adds custom handling to the wrapped WriterHeader method.
|
||||||
|
func (rw *ResponseWriter) WriteHeader(code int) {
|
||||||
|
if rw.feeder.shouldTrackStatus(code) {
|
||||||
|
rw.feeder.submitToFeed(rw.request, code)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Continue with the original method.
|
||||||
|
rw.ResponseWriter.WriteHeader(code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rw *ResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||||
|
hijacker, ok := rw.ResponseWriter.(http.Hijacker)
|
||||||
|
if !ok {
|
||||||
|
return nil, nil, fmt.Errorf("%T is not a http.Hijacker", rw.ResponseWriter)
|
||||||
|
}
|
||||||
|
|
||||||
|
return hijacker.Hijack()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rw *ResponseWriter) Flush() {
|
||||||
|
if flusher, ok := rw.ResponseWriter.(http.Flusher); ok {
|
||||||
|
flusher.Flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
30
umami.go
30
umami.go
|
|
@ -20,7 +20,7 @@ type Config struct {
|
||||||
// Debug enables debug logging, be prepared for flooding.
|
// Debug enables debug logging, be prepared for flooding.
|
||||||
Debug bool `json:"debug"`
|
Debug bool `json:"debug"`
|
||||||
// QueueSize defines the size of queue, i.e. the amount of events that are waiting to be submitted to Umami.
|
// QueueSize defines the size of queue, i.e. the amount of events that are waiting to be submitted to Umami.
|
||||||
QueueSize int
|
QueueSize int `json:"queueSize"`
|
||||||
|
|
||||||
// UmamiHost is the URL of the Umami instance.
|
// UmamiHost is the URL of the Umami instance.
|
||||||
UmamiHost string `json:"umamiHost"`
|
UmamiHost string `json:"umamiHost"`
|
||||||
|
|
@ -39,6 +39,8 @@ type Config struct {
|
||||||
// CreateNewWebsites when set to true, the plugin will create new websites using API, UmamiToken is required.
|
// CreateNewWebsites when set to true, the plugin will create new websites using API, UmamiToken is required.
|
||||||
CreateNewWebsites bool `json:"createNewWebsites"`
|
CreateNewWebsites bool `json:"createNewWebsites"`
|
||||||
|
|
||||||
|
// TrackErrors defines whether errors (status codes >= 400) should be tracked.
|
||||||
|
TrackErrors bool `json:"trackErrors"`
|
||||||
// TrackAllResources defines whether all requests for any resource should be tracked.
|
// TrackAllResources defines whether all requests for any resource should be tracked.
|
||||||
// By default, only requests that are believed to contain content are tracked.
|
// By default, only requests that are believed to contain content are tracked.
|
||||||
TrackAllResources bool `json:"trackAllResources"`
|
TrackAllResources bool `json:"trackAllResources"`
|
||||||
|
|
@ -61,6 +63,7 @@ func CreateConfig() *Config {
|
||||||
Disabled: false,
|
Disabled: false,
|
||||||
Debug: false,
|
Debug: false,
|
||||||
QueueSize: 1000,
|
QueueSize: 1000,
|
||||||
|
TrackErrors: false,
|
||||||
|
|
||||||
UmamiHost: "",
|
UmamiHost: "",
|
||||||
UmamiToken: "",
|
UmamiToken: "",
|
||||||
|
|
@ -96,6 +99,7 @@ type UmamiFeeder struct {
|
||||||
websites map[string]string
|
websites map[string]string
|
||||||
createNewWebsites bool
|
createNewWebsites bool
|
||||||
|
|
||||||
|
trackErrors bool
|
||||||
trackAllResources bool
|
trackAllResources bool
|
||||||
trackExtensions []string
|
trackExtensions []string
|
||||||
|
|
||||||
|
|
@ -123,6 +127,7 @@ func New(ctx context.Context, next http.Handler, config *Config, name string) (h
|
||||||
websites: config.Websites,
|
websites: config.Websites,
|
||||||
createNewWebsites: config.CreateNewWebsites,
|
createNewWebsites: config.CreateNewWebsites,
|
||||||
|
|
||||||
|
trackErrors: config.TrackErrors,
|
||||||
trackAllResources: config.TrackAllResources,
|
trackAllResources: config.TrackAllResources,
|
||||||
trackExtensions: config.TrackExtensions,
|
trackExtensions: config.TrackExtensions,
|
||||||
|
|
||||||
|
|
@ -225,7 +230,16 @@ func (h *UmamiFeeder) verifyConfig(config *Config) error {
|
||||||
|
|
||||||
func (h *UmamiFeeder) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
func (h *UmamiFeeder) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||||
if !h.isDisabled && h.shouldTrack(req) {
|
if !h.isDisabled && h.shouldTrack(req) {
|
||||||
h.submitToFeed(req)
|
// If the resource should be reported, we wrap the response writer and check the status code before reporting
|
||||||
|
wrappedResponseWriter := &ResponseWriter{
|
||||||
|
ResponseWriter: rw,
|
||||||
|
request: req,
|
||||||
|
feeder: h,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Continue with next handler.
|
||||||
|
h.next.ServeHTTP(wrappedResponseWriter, req)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
h.next.ServeHTTP(rw, req)
|
h.next.ServeHTTP(rw, req)
|
||||||
|
|
@ -316,6 +330,18 @@ func (h *UmamiFeeder) shouldTrackResource(url string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *UmamiFeeder) shouldTrackStatus(statusCode int) (report bool) {
|
||||||
|
if statusCode >= 400 {
|
||||||
|
if h.trackErrors {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
h.debug("not reporting %d error", statusCode)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (h *UmamiFeeder) error(message string) {
|
func (h *UmamiFeeder) error(message string) {
|
||||||
if h.logHandler != nil {
|
if h.logHandler != nil {
|
||||||
now := time.Now().Format("2006-01-02T15:04:05Z")
|
now := time.Now().Format("2006-01-02T15:04:05Z")
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ var headersToCopy = []string{
|
||||||
// Copied and adapted from https://github.com/safing/plausiblefeeder/blob/master/event.go
|
// Copied and adapted from https://github.com/safing/plausiblefeeder/blob/master/event.go
|
||||||
// Licensed as MIT license
|
// Licensed as MIT license
|
||||||
|
|
||||||
func (h *UmamiFeeder) submitToFeed(req *http.Request) {
|
func (h *UmamiFeeder) submitToFeed(req *http.Request, code int) {
|
||||||
body := SendBody{
|
body := SendBody{
|
||||||
Payload: SendPayload{
|
Payload: SendPayload{
|
||||||
Hostname: parseDomainFromHost(req.Host),
|
Hostname: parseDomainFromHost(req.Host),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue