package reportscollector import ( "errors" "fmt" "log" "mime" "net/http" "github.com/prometheus/client_golang/prometheus" ) var ErrNoMatch = errors.New("no match") type Handler interface { Parse(string, *http.Request) ([]Event, error) } type Sink interface { Send(Event) } type Collector struct { handlers []Handler sink Sink } func NewCollector(sink Sink, handlers ...Handler) *Collector { return &Collector{ handlers: handlers, sink: sink, } } func (c *Collector) ServeHTTP(w http.ResponseWriter, req *http.Request) { switch req.Method { case http.MethodPost: case http.MethodOptions: w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Methods", "POST") w.Header().Set("Access-Control-Allow-Headers", "content-type") w.Header().Set("Access-Control-Max-Age", "86400") w.WriteHeader(http.StatusNoContent) return default: http.Error(w, "Bad method", http.StatusMethodNotAllowed) return } ct, _, err := mime.ParseMediaType(req.Header.Get("Content-Type")) if err != nil { http.Error(w, fmt.Sprintf("Bad Content-Type: %v", err.Error()), http.StatusBadRequest) log.Printf("error parsing content-type: %v", err) return } // Find a handler that can successfully parse the request, and // get a list of Events. var events []Event matched := false hloop: for _, h := range c.handlers { var err error events, err = h.Parse(ct, req) switch err { case ErrNoMatch: continue case nil: matched = true w.WriteHeader(http.StatusOK) break hloop default: log.Printf("error parsing report (%s): %v", ct, err) http.Error(w, err.Error(), http.StatusBadRequest) return } } if !matched { log.Printf("no matching handlers for \"%s\"", ct) http.Error(w, "No matching handlers", http.StatusBadRequest) return } // Augment the Events with additional information obtained // from the HTTP request, and send them to the forwarder. for _, e := range events { c.sink.Send(e) reportsByType.WithLabelValues( e.GetString("type"), e.GetString("domain")).Inc() } } var ( reportsByType = prometheus.NewCounterVec( prometheus.CounterOpts{ Name: "reports_total", Help: "Number of reports by type.", }, []string{"type", "domain"}, ) ) func init() { prometheus.MustRegister(reportsByType) }