collector

package
v0.0.0-...-6f38d97 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 28, 2019 License: Apache-2.0 Imports: 13 Imported by: 0

Documentation

Overview

Package collector provides the basics of a NEL-compliant report collector.

Index

Constants

This section is empty.

Variables

View Source
var ErrDropped = errors.New("queue full, report dropped")

ErrDropped is returned from ProcessReports when the queue is full and the report is dropped.

Functions

func DecodeRawReports

func DecodeRawReports(b []byte, reports *[]NelReport) error

DecodeRawReports unmarshals an array of NelReports without using our custom spec-aware JSON parsing rules. It's the inverse of EncodeRawReports.

func EncodeRawBatch

func EncodeRawBatch(batch *ReportBatch) ([]byte, error)

EncodeRawBatch marshals a batch of NelReports, including any custom annotations, without using our custom spec-aware JSON parsing rules.

func EncodeRawReports

func EncodeRawReports(reports []NelReport) ([]byte, error)

EncodeRawReports marshals an array of NelReports without using our custom spec-aware JSON parsing rules, instead dumping out the content exactly as it looks in Go. This is used extensively in test cases to compare the results of parsing and annotating against golden files.

func PrintBatchAsCLF

func PrintBatchAsCLF(batch *ReportBatch, w io.Writer)

PrintBatchAsCLF prints out a summary of each report in the batch using a format not unlike the format of an Apache access.log file.

func RegisterContextReportLoaderFunc

func RegisterContextReportLoaderFunc(name string, loader func(ctx context.Context, config toml.Primitive) (ReportProcessor, error))

RegisterContextReportLoaderFunc registers a context-aware function that can load a particular kind of report processor.

func RegisterReportLoader

func RegisterReportLoader(name string, loader ReportLoader)

RegisterReportLoader registers a ReportLoader for a particular kind of report processor.

func RegisterReportLoaderFunc

func RegisterReportLoaderFunc(name string, loader func(config toml.Primitive) (ReportProcessor, error))

RegisterReportLoaderFunc registers a function that can load a particular kind of report processor.

Types

type Annotations

type Annotations struct {
	Annotations map[string]interface{}
}

Annotations lets you attach an arbitrary collection of extra data to each individual report, and to each report batch. Each annotation has a name and an arbitrary type; it's up to you to make sure that your processors don't make conflicting assumptions about the type of an annotation with a particular name.

func (*Annotations) AnnotationWriter

func (a *Annotations) AnnotationWriter(name string) io.Writer

AnnotationWriter returns an io.Writer that can be used to build up the content of a []byte annotation.

func (*Annotations) GetAnnotation

func (a *Annotations) GetAnnotation(name string) interface{}

GetAnnotation returns the annotation with the given name, or nil if there isn't one.

func (*Annotations) GetOrAddAnnotation

func (a *Annotations) GetOrAddAnnotation(name string, defaultValue interface{}) interface{}

GetOrAddAnnotation returns the annotation with the given name, if it exists. If it doesn't, then we save `defaultValue` as the new value for this annotation, and return it.

func (*Annotations) SetAnnotation

func (a *Annotations) SetAnnotation(name string, value interface{})

SetAnnotation adds an annotation, overwriting any existing annotation with the same name.

type Clock

type Clock interface {
	Now() time.Time
}

Clock lets you override how a pipeline assigns timestamps to each report. The default is to use time.Now; you can provide a custom implementation to get reproducible timestamps in test cases.

type ContextReportLoaderFunc

type ContextReportLoaderFunc func(ctx context.Context, config toml.Primitive) (ReportProcessor, error)

ContextReportLoaderFunc allows you to register a simple function (which needs access to a Context) as a ReportLoader.

func (ContextReportLoaderFunc) Load

Load defers to a ContextReportLoaderFunc to load a ReportProcessor from the contents of a configuration file.

type HandlerCloser

type HandlerCloser interface {
	Close()
	http.Handler
}

HandlerCloser is an interface for a http.Handler that processes data asynchronously and therefore must be closed. Once Close is called, the caller must ensure that no further calls to ServeHTTP are made.

type HotSwap

type HotSwap struct {
	// contains filtered or unexported fields
}

A HotSwap wraps a HandlerCloser and adds the support for a new handler to swapped in the middle of execution with no interruption to processing. In this manner, an external listener can load a new configuration, create a new Handler, and call Swap. In a threadsafe manner, the old Handler will be replaced and all future calls to ServeHTTP will use the new version of the handler.

func (*HotSwap) Close

func (h *HotSwap) Close()

Close closes the contained HandlerCloser, first ensuring that all in-progress calls to ServeHTTP have completed. It is up to the caller to ensure that no calls to ServeHTTP are made after this function has started.

func (*HotSwap) ServeHTTP

func (h *HotSwap) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP delegates incoming requests to the contained handler in a thread safe manner.

func (*HotSwap) Swap

func (h *HotSwap) Swap(hc HandlerCloser)

Swap takes a new Pipeline and atomicly exchanges a new handler for all future processing. It ensures that all active calls to ServeHTTP are done and then closes the old Pipeline

type NelReport

type NelReport struct {
	// The number of milliseconds between when the report was generated by
	// the user agent and when it was uploaded.
	Age int
	// The type of report.  For NEL, this will be "network-error".
	ReportType string
	// The URL of the request that this report describes.
	URL string
	// UserAgent represents the value of the User-Agent header in the request that the report is about
	UserAgent string
	// The referrer information of the request, as determined by the
	// referrer policy associated with its client.
	Referrer string
	// The active sampling rate for this request, expressed as a fraction
	// between 0.0 and 1.0 (inclusive).
	SamplingFraction float32
	// The IP address of the host to which the user agent set the request.
	ServerIP string
	// The ALPN ID  of the network protocol used to fetch the resource.
	Protocol string
	// The method of the HTTP request (e.g. GET, POST)
	Method string
	// The status code of the HTTP response, if available.
	StatusCode int
	// The elapsed number of milliseconds between the start of the resource
	// fetch and when it was aborted by the user agent.
	ElapsedTime int
	// The phase of the request in which the failure occurred. One of
	// {dns, connection, application}; a successful request always has a value of application
	Phase string
	// The description of the error type.  For reports about successful
	// requests, this will be "ok".  See the NEL spec for the authoritative
	// list of possible values for failed requests.
	Type string

	// For non-NEL reports, this will contain the unparsed JSON content of
	// the report's `body` field.
	RawBody []byte

	// An arbitrary set of extra data that you can attach to your reports.
	Annotations
}

A NelReport describes a single network error report.

(The name is a bit of a misnomer; it can also represent other report payloads uploaded via the Reporting API, in which case ReportType will tell you what kind of report it is, and RawBody will contain the unparsed JSON `body` field. It can also represent information about successful HTTP requests, collected and delivered via a user agent's NEL stack, in which case the Type field will be "ok".)

func (NelReport) MarshalJSON

func (r NelReport) MarshalJSON() ([]byte, error)

MarshalJSON marshals a NEL report into a JSON payload as defined by the Reporting and NEL specs. (It correctly handles the nested structure of the JSON, extracting the fields of the non-nested NelReport type.)

func (*NelReport) UnmarshalJSON

func (r *NelReport) UnmarshalJSON(b []byte) error

UnmarshalJSON unmarshals the JSON payload as defined by the Reporting and NEL specs into a NelReport object. (It correctly handles the nested structure of the JSON, filling in the fields of the non-nested NelReport type.)

type Pipeline

type Pipeline struct {
	// contains filtered or unexported fields
}

Pipeline is a series of processors that should be applied to each report that the collector receives. It uses a fixed number of workers to process the reports and a fixed sized queue that the workers read from. If the queue fills, reports are dropped. Pipeline{} is not a usable instance, use NewPipeline for production and NewTestPipeline* in tests.

func NewPipeline

func NewPipeline(bufferSize int64, numWorkers int) *Pipeline

NewPipeline creates a new Pipeline with a specified buffer size and number of workers.

func NewTestPipeline

func NewTestPipeline(clock Clock) *Pipeline

NewTestPipeline creates a new Pipeline with a specified clock. This should only be used for testing.

func NewTestPipelineWithBuffer

func NewTestPipelineWithBuffer(clock Clock, bufferSize int64) *Pipeline

NewTestPipelineWithBuffer creates a new Pipeline with a specified buffer size and clock. This should only be used for testing.

func (*Pipeline) AddProcessor

func (p *Pipeline) AddProcessor(processor ReportProcessor)

AddProcessor adds a new processor to the pipeline.

func (*Pipeline) Close

func (p *Pipeline) Close()

Close stops the processing, such that anything in the queue gets processed, but nothing is added. It then waits until all processing workers have completed. All calls to ProcessReports must complete before Close is called, otherwise it will cause a panic.

func (*Pipeline) LoadFromConfig

func (p *Pipeline) LoadFromConfig(ctx context.Context, configBytes []byte) error

LoadFromConfig loads pipeline processors based on the contents of a TOML configuration file, and adds them to the pipeline.

The configuration must have sections named `processor`, each of which defines one processor that should be added to the pipeline. For instance, this configuration could look like:

[[processor]]
type = "KeepNelReports"

[[processor]]
type = "DumpReportsAsCLF"
use_utc = true

The `type` field of each element identifies which kind of processor to add; any additional fields let you specify any processor-specific configuration.

func (*Pipeline) ProcessReports

func (p *Pipeline) ProcessReports(ctx context.Context, w http.ResponseWriter, r *http.Request) error

ProcessReports extracts reports from a POST upload payload, as defined by the Reporting spec, and runs all of the processors in the pipeline against each report. Returns ErrDropped if the request was dropped due to a full queue and nil on success. All other errors indicate something wrong with the request.

func (*Pipeline) ServeHTTP

func (p *Pipeline) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP handles POST report uploads, extracting the payload and handing it off to ProcessReports for processing.

type ReportBatch

type ReportBatch struct {
	Reports []NelReport

	// When this batch was received by the collector
	Time time.Time

	// The URL that was used to upload the report.
	CollectorURL url.URL

	// The IP address of the client that uploaded the batch of reports.  You can
	// typically assume that's the same IP address that was used for the original
	// requests.  The IP address will be encoded as a string; for example,
	// "192.0.2.1" or "2001:db8::2".
	ClientIP string

	// The user agent of the client that uploaded the batch of reports.
	ClientUserAgent string

	// The key-value pairs of the HTTP header that is received by the collector.
	// This can be used to get additional information. One example is to get the
	// remote address of the client when the collector runs behind a proxy.
	Header http.Header

	// An arbitrary set of extra data that you can attach to this batch of
	// reports.
	Annotations
}

ReportBatch is a collection of reports that should all be processed together. We will create a new batch for each upload that the collector receives. Certain processors might join batches together or split them up.

func NewReportBatch

func NewReportBatch(r *http.Request, clock Clock) (*ReportBatch, error)

NewReportBatch takes a HTTP request and a clock and fills in a ReportBatch, returning an error if parsing fails.

type ReportLoader

type ReportLoader interface {
	Load(ctx context.Context, config toml.Primitive) (ReportProcessor, error)
}

ReportLoader is an interface that knows how to load a ReportProcessor at runtime via the contents of a TOML configuration file.

type ReportLoaderFunc

type ReportLoaderFunc func(config toml.Primitive) (ReportProcessor, error)

ReportLoaderFunc allows you to register a simple function as a ReportLoader.

func (ReportLoaderFunc) Load

Load defers to a ReportLoaderFunc to load a ReportProcessor from the contents of a configuration file.

type ReportProcessor

type ReportProcessor interface {
	// ProcessReports handles a single batch of reports.  You have full control
	// over the contents of the batch; for instance, you can remove elements or
	// update their contents, if appropriate.
	ProcessReports(ctx context.Context, batch *ReportBatch)
}

A ReportProcessor implements one discrete processing step for handling uploaded reports. There are several predefined processors, which you can use to filter or publish reports. You can also implement custom annotation steps if you want to add additional data to a report before publishing.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL