pirsch

package module
v2.2.5 Latest Latest
Warning

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

Go to latest
Published: Jun 16, 2021 License: AGPL-3.0 Imports: 33 Imported by: 0

README

Pirsch

Go Reference Go Report Card Chat on Discord

Pirsch is a server side, no-cookie, drop-in and privacy focused tracking solution for Go. Integrated into a Go application it enables you to track HTTP traffic without invading the privacy of your visitors. The visualization of the data (dashboard) is not part of this project.

The name is in German and refers to a special kind of hunt: the hunter carefully and quietly enters the area to be hunted, he stalks against the wind in order to get as close as possible to the prey without being noticed.

If you're looking for a managed solution with an easy-to-use API and JavaScript integration, check out https://pirsch.io/.

How does it work?

Pirsch generates a unique fingerprint for each visitor. The fingerprint is a hash of the visitors IP, User-Agent, the date, and a salt. The date guarantees that the data is separated by day, so visitors can only be tracked for up to one day.

Each time a visitor opens your page, Pirsch will store a hit. The hits are analyzed using the Analyzer to extract meaningful data.

The tracking works without invading the visitor's privacy as no cookies are used nor required. Pirsch can track visitors using ad blockers that block trackers like Google Analytics.

Features

Pirsch tracks the following data:

  • unique visitor count per day, path, and hour
  • session count
  • bounce rate
  • view count
  • growth (unique visitors, sessions, bounces, views, average session duration)
  • average time on page
  • average session duration
  • languages
  • operating system and browser (including versions)
  • referrers
  • countries
  • platform
  • screen size
  • UTM query parameters for campaign tracking
  • entry and exit pages

All timestamps are stored as UTC. Starting with version 2.1, the results can be transformed to the desired timezone. All data points belongs to an (optional) client, which can be used to split data between multiple domains for example. If you just integrate Pirsch into your application, you don't need to care about that field. But if you do, you need to set a client ID for all columns!

Usage

To store hits and statistics, Pirsch uses ClickHouse. Database migrations can be run manually be executing the migrations steps in schema or by using the automatic migration (make sure you set x-multi-statement to true).

Server-side tracking

Here is a quick demo on how to use the library:

// Migrate the database.
pirsch.Migrate("clickhouse://127.0.0.1:9000?x-multi-statement=true")

// Create a new ClickHouse client to save hits.
store, _ := pirsch.NewClient("tcp://127.0.0.1:9000", nil)

// Set up a default tracker with a salt.
// This will buffer and store hits and generate sessions by default.
tracker := pirsch.NewTracker(store, "salt", nil)

// Create a handler to serve traffic.
// We prevent tracking resources by checking the path. So a file on /my-file.txt won't create a new hit
// but all page calls will be tracked.
http.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    if r.URL.Path == "/" {
        go tracker.Hit(r, nil)
    }

    w.Write([]byte("<h1>Hello World!</h1>"))
}))

// And finally, start the server.
// We don't flush hits on shutdown but you should add that in a real application by calling Tracker.Flush().
log.Println("Starting server on port 8080...")
http.ListenAndServe(":8080", nil)

The secret salt passed to NewTracker should not be known outside your organization as it can be used to generate fingerprints equal to yours. Note that while you can generate the salt at random, the fingerprints will change too. To get reliable data configure a fixed salt and treat it like a password.

To analyze hits and processed data you can use the Analyzer, which provides convenience functions to extract useful information.

// This also needs access to the store.
analyzer := pirsch.NewAnalyzer(store)

// As an example, lets extract the total number of visitors.
// The filter is used to specify the time frame you're looking at (days) and is optional.
// If you pass nil, the Analyzer returns statistics for all hits (be careful about that!).
visitors, err := analyzer.Visitors(&pirsch.Filter{
    From: yesterday(),
    To: today()
})
Client-side tracking

You can also track visitors on the client side by adding pirsch.js to your website. It will perform a GET request to the configured endpoint.

<!-- add the tracking script to the head area and configure it using attributes -->
<script type="text/javascript" src="js/pirsch.js" id="pirschjs"
        data-endpoint="/count"
        data-client-id="42"
        data-track-localhost
        data-param-optional-param="test"></script>

The parameters are configured through HTML attributes. All of them are optional, except for the id. Here is a list of the possible options.

Option Description Default
data-endpoint The endpoint to call. This can be a local path, like /tracking, or a complete URL, like http://mywebsite.com/tracking. It must not contain any parameters. /pirsch
data-client-id The client ID to use, in case you plan to track multiple websites using the same backend, or you want to split the data. Note that the client ID must be validated in the backend. 0 (no client)
data-track-localhost Enable tracking hits on localhost. This is used for testing purposes only. false
data-param-* Additional parameters to send with the request. The name send is everything after data-param-. (no parameters)

To track the hits you need to call Hit from the endpoint that you configured for pirsch.js. Here is a simple example.

// Create an endpoint to handle client tracking requests.
// HitOptionsFromRequest is a utility function to process the required parameters.
// You might want to additional checks, like for the client ID.
http.Handle("/count", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    tracker.Hit(r, pirsch.HitOptionsFromRequest(r))
}))

HitOptionsFromRequest will read the parameters send by pirsch.js and returns a new HitOptions object that can be passed to Hit. You might want to split these steps into two, to run additional checks for the parameters that were sent by the user.

Mapping IPs to countries

Pirsch uses MaxMind's GeoLite2 database to map IPs to countries. The database is not included, so you need to download it yourself. IP mapping is optional, it must explicitly be enabled by setting the GeoDB attribute of the TrackerConfig or through the HitOptions when calling HitFromRequest.

  1. create an account at MaxMind
  2. generate a new license key
  3. call GetGeoLite2 with the path you would like to extract the tarball to and pass your license key
  4. create a new GeoDB by using NewGeoDB and the file you downloaded and extracted using the step before

The GeoDB should be updated on a regular basis. The Tracker has a method SetGeoDB to update the GeoDB at runtime (thread-safe).

Documentation

Read the full documentation for details, check out demos, or read the article at https://marvinblum.de/blog/server-side-tracking-without-cookies-in-go-OxdzmGZ1Bl.

Build pirsch.js

To minify pirsch.js to pirsch.min.js you need to run npm i and npm run minify inside the js directory.

Changelog

See CHANGELOG.md.

Contribution

Contributions are welcome! Please open a pull requests for your changes and tickets in case you would like to discuss something or have a question.

To run the tests you'll need a Postgres database, and a schema called pirsch. The user and password are set to postgres.

Note that we only accept pull requests if you transfer the ownership of your contribution to us. As we also offer a managed commercial solution with this library at its core, we want to make sure we can keep control over the source code.

License

GNU AGPLv3

Documentation

Index

Constants

View Source
const (
	// PlatformDesktop filters for everything on desktops.
	PlatformDesktop = "desktop"

	// PlatformMobile filters for everything on mobile devices.
	PlatformMobile = "mobile"

	// PlatformUnknown filters for everything where the platform is unspecified.
	PlatformUnknown = "unknown"
)
View Source
const (
	// BrowserChrome represents the Chrome and Chromium browser.
	BrowserChrome = "Chrome"

	// BrowserFirefox represents the Firefox browser.
	BrowserFirefox = "Firefox"

	// BrowserSafari  represents the Safari browser.
	BrowserSafari = "Safari"

	// BrowserOpera represents the Opera browser.
	BrowserOpera = "Opera"

	// BrowserEdge represents the Edge browser.
	BrowserEdge = "Edge"

	// BrowserIE represents the Internet Explorer browser.
	BrowserIE = "IE"

	// OSWindows represents the Windows operating system.
	OSWindows = "Windows"

	// OSMac represents the Mac operating system.
	OSMac = "Mac"

	// OSLinux represents a Linux distribution.
	OSLinux = "Linux"

	// OSAndroid represents the Android operating system.
	OSAndroid = "Android"

	// OSiOS represents the iOS operating system.
	OSiOS = "iOS"

	// OSWindowsMobile represents the Windows Mobile operating system.
	OSWindowsMobile = "Windows Mobile"
)
View Source
const (

	// GeoLite2Filename is the default filename of the GeoLite2 database.
	GeoLite2Filename = "GeoLite2-Country.mmdb"
)

Variables

View Source
var (
	// ErrNoPeriodOrDay is returned in case no period or day was specified to calculate the growth rate.
	ErrNoPeriodOrDay = errors.New("no period or day specified")
)
View Source
var NullClient = int64(0)

NullClient is a placeholder for no client (0).

View Source
var ScreenClasses = []screenClass{
	{1440, "XXL"},
	{1024, "XL"},
	{800, "L"},
	{600, "M"},
	{415, "S"},
}

ScreenClasses is a list of typical screen sizes used to group resolutions. Everything below is considered "XS" (tiny).

Functions

func Fingerprint

func Fingerprint(r *http.Request, salt string, timezone *time.Location) string

Fingerprint returns a hash for given request, salt, and timezone. The hash is unique for the visitor.

func GetGeoLite2

func GetGeoLite2(path, licenseKey string) error

GetGeoLite2 downloads and unpacks the MaxMind GeoLite2 database. The tarball is downloaded and unpacked at the provided path. The directories will created if required. The license key is used for the download and must be provided for a registered account. Please refer to MaxMinds website on how to do that: https://dev.maxmind.com/geoip/geoip2/geolite2/ The database should be updated on a regular basis.

func GetScreenClass

func GetScreenClass(width int) string

GetScreenClass returns the screen class for given width in pixels.

func IgnoreHit

func IgnoreHit(r *http.Request) bool

IgnoreHit returns true, if a hit should be ignored for given request, or false otherwise. The easiest way to track visitors is to use the Tracker.

func Migrate

func Migrate(connection string) error

Migrate runs the database migration for given connection string. This will use the embedded schema migration scripts. You have to set the x-multi-statement to true, or else it will fail to run the queries.

func RunAtMidnight

func RunAtMidnight(f func()) context.CancelFunc

RunAtMidnight calls given function on each day of month on midnight (UTC), unless it is cancelled by calling the cancel function.

func Today

func Today() time.Time

Today returns the date for today without time at UTC.

Types

type ActiveVisitorStats

type ActiveVisitorStats struct {
	Path     string `json:"path"`
	Visitors int    `json:"visitors"`
}

ActiveVisitorStats is the result type for active visitor statistics.

type Analyzer

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

Analyzer provides an interface to analyze statistics.

func NewAnalyzer

func NewAnalyzer(store Store) *Analyzer

NewAnalyzer returns a new Analyzer for given Store.

func (*Analyzer) ActiveVisitors

func (analyzer *Analyzer) ActiveVisitors(filter *Filter, duration time.Duration) ([]ActiveVisitorStats, int, error)

ActiveVisitors returns the active visitors per path and the total number of active visitors for given duration. Use time.Minute*5 for example to get the active visitors for the past 5 minutes.

func (*Analyzer) AvgSessionDuration

func (analyzer *Analyzer) AvgSessionDuration(filter *Filter) ([]TimeSpentStats, error)

AvgSessionDuration returns the average session duration grouped by day.

func (*Analyzer) AvgTimeOnPage

func (analyzer *Analyzer) AvgTimeOnPage(filter *Filter) ([]TimeSpentStats, error)

AvgTimeOnPage returns the average time on page grouped by day.

func (*Analyzer) AvgTimeOnPages

func (analyzer *Analyzer) AvgTimeOnPages(filter *Filter) ([]TimeSpentStats, error)

AvgTimeOnPages returns the average time on page grouped by path.

func (*Analyzer) Browser

func (analyzer *Analyzer) Browser(filter *Filter) ([]BrowserStats, error)

Browser returns the visitor count grouped by browser.

func (*Analyzer) BrowserVersion added in v2.2.2

func (analyzer *Analyzer) BrowserVersion(filter *Filter) ([]BrowserVersionStats, error)

BrowserVersion returns the visitor count grouped by browser and version.

func (*Analyzer) Countries

func (analyzer *Analyzer) Countries(filter *Filter) ([]CountryStats, error)

Countries returns the visitor count grouped by country.

func (*Analyzer) EntryPages added in v2.2.0

func (analyzer *Analyzer) EntryPages(filter *Filter) ([]EntryStats, error)

EntryPages returns the visitor count and time on page grouped by path for the first page visited.

func (*Analyzer) ExitPages added in v2.2.0

func (analyzer *Analyzer) ExitPages(filter *Filter) ([]ExitStats, error)

ExitPages returns the visitor count and time on page grouped by path for the last page visited.

func (*Analyzer) Growth

func (analyzer *Analyzer) Growth(filter *Filter) (*Growth, error)

Growth returns the growth rate for visitor count, session count, bounces, views, and average session duration or average time on page (if path is set). The growth rate is relative to the previous time range or day. The period or day for the filter must be set, else an error is returned.

func (*Analyzer) Languages

func (analyzer *Analyzer) Languages(filter *Filter) ([]LanguageStats, error)

Languages returns the visitor count grouped by language.

func (*Analyzer) OS

func (analyzer *Analyzer) OS(filter *Filter) ([]OSStats, error)

OS returns the visitor count grouped by operating system.

func (*Analyzer) OSVersion added in v2.2.2

func (analyzer *Analyzer) OSVersion(filter *Filter) ([]OSVersionStats, error)

OSVersion returns the visitor count grouped by operating systems and version.

func (*Analyzer) PageConversions added in v2.2.5

func (analyzer *Analyzer) PageConversions(filter *Filter) (*PageConversionsStats, error)

PageConversions returns the visitor count, views, and conversion rate. This function is supposed to be used with the Filter.PathPattern, to list page conversions.

func (*Analyzer) Pages

func (analyzer *Analyzer) Pages(filter *Filter) ([]PageStats, error)

Pages returns the visitor count, session count, bounce rate, views, and average time on page grouped by path.

func (*Analyzer) Platform

func (analyzer *Analyzer) Platform(filter *Filter) (*PlatformStats, error)

Platform returns the visitor count grouped by platform.

func (*Analyzer) Referrer

func (analyzer *Analyzer) Referrer(filter *Filter) ([]ReferrerStats, error)

Referrer returns the visitor count and bounce rate grouped by referrer.

func (*Analyzer) ScreenClass

func (analyzer *Analyzer) ScreenClass(filter *Filter) ([]ScreenClassStats, error)

ScreenClass returns the visitor count grouped by screen class.

func (*Analyzer) TotalSessionDuration

func (analyzer *Analyzer) TotalSessionDuration(filter *Filter) (int, error)

TotalSessionDuration returns the total session duration in seconds.

func (*Analyzer) TotalTimeOnPage

func (analyzer *Analyzer) TotalTimeOnPage(filter *Filter) (int, error)

TotalTimeOnPage returns the total time on page in seconds.

func (*Analyzer) UTMCampaign

func (analyzer *Analyzer) UTMCampaign(filter *Filter) ([]UTMCampaignStats, error)

UTMCampaign returns the visitor count grouped by utm source.

func (*Analyzer) UTMContent

func (analyzer *Analyzer) UTMContent(filter *Filter) ([]UTMContentStats, error)

UTMContent returns the visitor count grouped by utm source.

func (*Analyzer) UTMMedium

func (analyzer *Analyzer) UTMMedium(filter *Filter) ([]UTMMediumStats, error)

UTMMedium returns the visitor count grouped by utm medium.

func (*Analyzer) UTMSource

func (analyzer *Analyzer) UTMSource(filter *Filter) ([]UTMSourceStats, error)

UTMSource returns the visitor count grouped by utm source.

func (*Analyzer) UTMTerm

func (analyzer *Analyzer) UTMTerm(filter *Filter) ([]UTMTermStats, error)

UTMTerm returns the visitor count grouped by utm source.

func (*Analyzer) VisitorHours

func (analyzer *Analyzer) VisitorHours(filter *Filter) ([]VisitorHourStats, error)

VisitorHours returns the visitor count grouped by time of day.

func (*Analyzer) Visitors

func (analyzer *Analyzer) Visitors(filter *Filter) ([]VisitorStats, error)

Visitors returns the visitor count, session count, bounce rate, views, and average session duration grouped by day.

type BrowserStats

type BrowserStats struct {
	MetaStats
	Browser string `json:"browser"`
}

BrowserStats is the result type for browser statistics.

type BrowserVersionStats added in v2.2.2

type BrowserVersionStats struct {
	MetaStats
	Browser        string `json:"browser"`
	BrowserVersion string `db:"browser_version" json:"browser_version"`
}

BrowserVersionStats is the result type for browser version statistics.

type Client

type Client struct {
	sqlx.DB
	// contains filtered or unexported fields
}

Client is a ClickHouse database client.

func NewClient

func NewClient(connection string, logger *log.Logger) (*Client, error)

NewClient returns a new client for given database connection string. The logger is optional.

func (*Client) Count

func (client *Client) Count(query string, args ...interface{}) (int, error)

Count implements the Store interface.

func (*Client) Get

func (client *Client) Get(result interface{}, query string, args ...interface{}) error

Get implements the Store interface.

func (*Client) SaveHits

func (client *Client) SaveHits(hits []Hit) error

SaveHits implements the Store interface.

func (*Client) Select

func (client *Client) Select(results interface{}, query string, args ...interface{}) error

Select implements the Store interface.

func (*Client) Session

func (client *Client) Session(clientID int64, fingerprint string, maxAge time.Time) (string, time.Time, time.Time, error)

Session implements the Store interface.

type CountryStats

type CountryStats struct {
	MetaStats
	CountryCode string `db:"country_code" json:"country_code"`
}

CountryStats is the result type for country statistics.

type EntryStats added in v2.2.1

type EntryStats struct {
	Path                    string `json:"path"`
	Visitors                int    `json:"visitors"`
	Entries                 int    `json:"entries"`
	AverageTimeSpentSeconds int    `db:"average_time_spent_seconds" json:"average_time_spent_seconds"`
}

EntryStats is the result type for entry page statistics.

type ExitStats added in v2.2.1

type ExitStats struct {
	Path     string  `json:"path"`
	Visitors int     `json:"visitors"`
	Exits    int     `json:"exits"`
	ExitRate float64 `db:"exit_rate" json:"exit_rate"`
}

ExitStats is the result type for exit page statistics.

type Filter

type Filter struct {
	// ClientID is the optional.
	ClientID int64

	// Timezone sets the timezone used to interpret dates and times.
	// It will be set to UTC by default.
	Timezone *time.Location

	// From is the start date of the selected period.
	From time.Time

	// To is the end date of the selected period.
	To time.Time

	// Day is an exact match for the result set ("on this day").
	Day time.Time

	// Start is the start date and time of the selected period.
	Start time.Time

	// Path filters for the path.
	// Note that if this and PathPattern are both set, Path will be preferred.
	Path string

	// PathPattern filters for the path using a (ClickHouse supported) regex pattern.
	// Note that if this and Path are both set, Path will be preferred.
	// Examples for useful patterns (all case-insensitive, * is used for every character but slashes, ** is used for all characters including slashes):
	//  (?i)^/path/[^/]+$ // matches /path/*
	//  (?i)^/path/[^/]+/.* // matches /path/*/**
	//  (?i)^/path/[^/]+/slashes$ // matches /path/*/slashes
	//  (?i)^/path/.+/slashes$ // matches /path/**/slashes
	PathPattern string

	// Language filters for the ISO language code.
	Language string

	// Country filters for the ISO country code.
	Country string

	// Referrer filters for the referrer.
	Referrer string

	// OS filters for the operating system.
	OS string

	// OSVersion filters for the operating system version.
	OSVersion string

	// Browser filters for the browser.
	Browser string

	// BrowserVersion filters for the browser version.
	BrowserVersion string

	// Platform filters for the platform (desktop, mobile, unknown).
	Platform string

	// ScreenClass filters for the screen class.
	ScreenClass string

	// UTMSource filters for the utm_source query parameter.
	UTMSource string

	// UTMMedium filters for the utm_medium query parameter.
	UTMMedium string

	// UTMCampaign filters for the utm_campaign query parameter.
	UTMCampaign string

	// UTMContent filters for the utm_content query parameter.
	UTMContent string

	// UTMTerm filters for the utm_term query parameter.
	UTMTerm string

	// Limit limits the number of results. Less or equal to zero means no limit.
	Limit int

	// IncludeAvgTimeOnPage indicates whether Analyzer.Pages should contain the average time on page or not.
	IncludeAvgTimeOnPage bool
}

Filter are all fields that can be used to filter the result sets.

func NewFilter

func NewFilter(clientID int64) *Filter

NewFilter creates a new filter for given client ID.

type GeoDB

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

GeoDB maps IPs to their geo location based on MaxMinds GeoLite2 or GeoIP2 database.

func NewGeoDB

func NewGeoDB(config GeoDBConfig) (*GeoDB, error)

NewGeoDB creates a new GeoDB for given database file. The file is loaded into memory, therefore it's not necessary to close the reader (see oschwald/maxminddb-golang documentatio). The database should be updated on a regular basis.

func (*GeoDB) CountryCode

func (db *GeoDB) CountryCode(ip string) string

CountryCode looks up the country code for given IP. If the IP is invalid it will return an empty string. The country code is returned in lowercase.

type GeoDBConfig

type GeoDBConfig struct {
	// File is the path (including the filename) to the GeoLite2 country database file.
	// See GeoLite2Filename for the required filename.
	File string

	// Logger is the log.Logger used for logging.
	// Note that this will log the IP address and should therefore only be used for debugging.
	// Set it to nil to disable logging for GeoDB.
	Logger *log.Logger
}

GeoDBConfig is the configuration for the GeoDB.

type Growth

type Growth struct {
	VisitorsGrowth  float64 `json:"visitors_growth"`
	ViewsGrowth     float64 `json:"views_growth"`
	SessionsGrowth  float64 `json:"sessions_growth"`
	BouncesGrowth   float64 `json:"bounces_growth"`
	TimeSpentGrowth float64 `json:"time_spent_growth"`
}

Growth represents the visitors, views, sessions, bounces, and average session duration growth between two time periods.

type Hit

type Hit struct {
	ClientID                  int64 `db:"client_id"`
	Fingerprint               string
	Time                      time.Time
	Session                   time.Time
	PreviousTimeOnPageSeconds int    `db:"previous_time_on_page_seconds"`
	UserAgent                 string `db:"user_agent"`
	Path                      string
	URL                       string
	Language                  string
	CountryCode               string `db:"country_code"`
	Referrer                  string
	ReferrerName              string `db:"referrer_name"`
	ReferrerIcon              string `db:"referrer_icon"`
	OS                        string
	OSVersion                 string `db:"os_version"`
	Browser                   string
	BrowserVersion            string `db:"browser_version"`
	Desktop                   bool
	Mobile                    bool
	ScreenWidth               int    `db:"screen_width"`
	ScreenHeight              int    `db:"screen_height"`
	ScreenClass               string `db:"screen_class"`
	UTMSource                 string `db:"utm_source"`
	UTMMedium                 string `db:"utm_medium"`
	UTMCampaign               string `db:"utm_campaign"`
	UTMContent                string `db:"utm_content"`
	UTMTerm                   string `db:"utm_term"`
}

Hit represents a single data point/page visit and is the central entity of Pirsch.

func HitFromRequest

func HitFromRequest(r *http.Request, salt string, options *HitOptions) Hit

HitFromRequest returns a new Hit for given request, salt and HitOptions. The salt must stay consistent to track visitors across multiple calls. The easiest way to track visitors is to use the Tracker.

func (Hit) String

func (hit Hit) String() string

String implements the Stringer interface.

type HitOptions

type HitOptions struct {
	// Client is the database client required to look up sessions.
	Client Store

	// Timezone is the the timezone used to create the fingerprint.
	// It will be set to UTC by default.
	Timezone *time.Location

	// ClientID is optionally saved with a hit to split the data between multiple clients.
	ClientID int64

	// SessionMaxAge defines the maximum time a session stays active.
	// A session is kept active if requests are made within the time frame.
	// Set to 15 minutes by default.
	SessionMaxAge time.Duration

	// URL can be set to manually overwrite the URL stored for this request.
	// This will also affect the Path, except it is set too.
	URL string

	// Path can be set to manually overwrite the path stored for the request.
	// This will also affect the URL.
	Path string

	// Referrer can be set to manually overwrite the referrer from the request.
	Referrer string

	// ReferrerDomainBlacklist is used to filter out unwanted referrers from the Referrer header.
	// This can be used to filter out traffic from your own site or subdomains.
	// To filter your own domain and subdomains, add your domain to the list and set ReferrerDomainBlacklistIncludesSubdomains to true.
	// This way the referrer for blog.mypage.com -> mypage.com won't be saved.
	ReferrerDomainBlacklist []string

	// ReferrerDomainBlacklistIncludesSubdomains set to true to include all subdomains in the ReferrerDomainBlacklist,
	// or else subdomains must explicitly be included in the blacklist.
	// If the blacklist contains domain.com, sub.domain.com and domain.com will be treated as equals.
	ReferrerDomainBlacklistIncludesSubdomains bool

	// ScreenWidth sets the screen width to be stored with the hit.
	ScreenWidth int

	// ScreenHeight sets the screen height to be stored with the hit.
	ScreenHeight int
	// contains filtered or unexported fields
}

HitOptions is used to manipulate the data saved on a hit.

func HitOptionsFromRequest

func HitOptionsFromRequest(r *http.Request) *HitOptions

HitOptionsFromRequest returns the HitOptions for given client request. This function can be used to accept hits from pirsch.js. Invalid parameters are ignored and left empty. You might want to add additional checks before calling HitFromRequest afterwards (like for the HitOptions.ClientID).

type LanguageStats

type LanguageStats struct {
	MetaStats
	Language string `json:"language"`
}

LanguageStats is the result type for language statistics.

type MetaStats

type MetaStats struct {
	Visitors         int     `json:"visitors"`
	RelativeVisitors float64 `db:"relative_visitors" json:"relative_visitors"`
}

MetaStats is the base for meta result types (languages, countries, ...).

type MockClient

type MockClient struct {
	Hits []Hit
	// contains filtered or unexported fields
}

MockClient is a mock Store implementation.

func NewMockClient

func NewMockClient() *MockClient

NewMockClient returns a new mock client.

func (*MockClient) Count

func (client *MockClient) Count(query string, args ...interface{}) (int, error)

Count implements the Store interface.

func (*MockClient) Get

func (client *MockClient) Get(result interface{}, query string, args ...interface{}) error

Get implements the Store interface.

func (*MockClient) SaveHits

func (client *MockClient) SaveHits(hits []Hit) error

SaveHits implements the Store interface.

func (*MockClient) Select

func (client *MockClient) Select(results interface{}, query string, args ...interface{}) error

Select implements the Store interface.

func (*MockClient) Session

func (client *MockClient) Session(clientID int64, fingerprint string, maxAge time.Time) (string, time.Time, time.Time, error)

Session implements the Store interface.

type OSStats

type OSStats struct {
	MetaStats
	OS string `json:"os"`
}

OSStats is the result type for operating system statistics.

type OSVersionStats added in v2.2.2

type OSVersionStats struct {
	MetaStats
	OS        string `json:"os"`
	OSVersion string `db:"os_version" json:"os_version"`
}

OSVersionStats is the result type for operating system version statistics.

type PageConversionsStats added in v2.2.5

type PageConversionsStats struct {
	Visitors int     `json:"visitors"`
	Views    int     `json:"views"`
	CR       float64 `json:"cr"`
}

PageConversionsStats is the result type for page conversions.

type PageStats

type PageStats struct {
	Path                    string  `json:"path"`
	Visitors                int     `json:"visitors"`
	Views                   int     `json:"views"`
	Sessions                int     `json:"sessions"`
	Bounces                 int     `json:"bounces"`
	RelativeVisitors        float64 `db:"relative_visitors" json:"relative_visitors"`
	RelativeViews           float64 `db:"relative_views" json:"relative_views"`
	BounceRate              float64 `db:"bounce_rate" json:"bounce_rate"`
	AverageTimeSpentSeconds int     `db:"average_time_spent_seconds" json:"average_time_spent_seconds"`
}

PageStats is the result type for page statistics.

type PlatformStats

type PlatformStats struct {
	PlatformDesktop         int     `db:"platform_desktop" json:"platform_desktop"`
	PlatformMobile          int     `db:"platform_mobile" json:"platform_mobile"`
	PlatformUnknown         int     `db:"platform_unknown" json:"platform_unknown"`
	RelativePlatformDesktop float64 `db:"relative_platform_desktop" json:"relative_platform_desktop"`
	RelativePlatformMobile  float64 `db:"relative_platform_mobile" json:"relative_platform_mobile"`
	RelativePlatformUnknown float64 `db:"relative_platform_unknown" json:"relative_platform_unknown"`
}

PlatformStats is the result type for platform statistics.

type ReferrerStats

type ReferrerStats struct {
	Referrer         string  `json:"referrer"`
	ReferrerName     string  `db:"referrer_name" json:"referrer_name"`
	ReferrerIcon     string  `db:"referrer_icon" json:"referrer_icon"`
	Visitors         int     `json:"visitors"`
	RelativeVisitors float64 `db:"relative_visitors" json:"relative_visitors"`
	Bounces          int     `json:"bounces"`
	BounceRate       float64 `db:"bounce_rate" json:"bounce_rate"`
}

ReferrerStats is the result type for referrer statistics.

type ScreenClassStats

type ScreenClassStats struct {
	MetaStats
	ScreenClass string `db:"screen_class" json:"screen_class"`
}

ScreenClassStats is the result type for screen class statistics.

type Store

type Store interface {
	// SaveHits saves new hits.
	SaveHits([]Hit) error

	// Session returns the last path, time, and session timestamp for given client, fingerprint, and maximum age.
	Session(int64, string, time.Time) (string, time.Time, time.Time, error)

	// Count returns the number of results for given query.
	Count(string, ...interface{}) (int, error)

	// Get returns a single result for given query.
	// The result must be a pointer.
	Get(interface{}, string, ...interface{}) error

	// Select returns the results for given query.
	// The results must be a pointer to a slice.
	Select(interface{}, string, ...interface{}) error
}

Store is the database storage interface.

type TimeSpentStats

type TimeSpentStats struct {
	Day                     time.Time `json:"day"`
	Path                    string    `json:"path"`
	AverageTimeSpentSeconds int       `db:"average_time_spent_seconds" json:"average_time_spent_seconds"`
}

TimeSpentStats is the result type for average time spent statistics (sessions, time on page).

type Tracker

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

Tracker provides methods to track requests. Make sure you call Stop to make sure the hits get stored before shutting down the server.

func NewTracker

func NewTracker(client Store, salt string, config *TrackerConfig) *Tracker

NewTracker creates a new tracker for given client, salt and config. Pass nil for the config to use the defaults. The salt is mandatory.

func (*Tracker) Flush

func (tracker *Tracker) Flush()

Flush flushes all hits to client that are currently buffered by the workers. Call Tracker.Stop to also save hits that are in the queue.

func (*Tracker) Hit

func (tracker *Tracker) Hit(r *http.Request, options *HitOptions)

Hit stores the given request. The request might be ignored if it meets certain conditions. The HitOptions, if passed, will overwrite the Tracker configuration. It's save (and recommended!) to call this function in its own goroutine.

func (*Tracker) SetGeoDB

func (tracker *Tracker) SetGeoDB(geoDB *GeoDB)

SetGeoDB sets the GeoDB for the Tracker. The call to this function is thread safe to enable live updates of the database. Pass nil to disable the feature.

func (*Tracker) Stop

func (tracker *Tracker) Stop()

Stop flushes and stops all workers.

type TrackerConfig

type TrackerConfig struct {
	// Worker sets the number of workers that are used to client hits.
	// Must be greater or equal to 1.
	Worker int

	// WorkerBufferSize is the size of the buffer used to client hits.
	// Must be greater than 0. The hits are stored in batch when the buffer is full.
	WorkerBufferSize int

	// WorkerTimeout sets the timeout used to client hits.
	// This is used to allow the workers to client hits even if the buffer is not full yet.
	// It's recommended to set this to a few seconds.
	// If you leave it 0, the default timeout is used, else it is limted to 60 seconds.
	WorkerTimeout time.Duration

	// ReferrerDomainBlacklist see HitOptions.ReferrerDomainBlacklist.
	ReferrerDomainBlacklist []string

	// ReferrerDomainBlacklistIncludesSubdomains see HitOptions.ReferrerDomainBlacklistIncludesSubdomains.
	ReferrerDomainBlacklistIncludesSubdomains bool

	// SessionMaxAge see HitOptions.SessionMaxAge.
	SessionMaxAge time.Duration

	// GeoDB enables/disabled mapping IPs to country codes.
	// Can be set/updated at runtime by calling Tracker.SetGeoDB.
	GeoDB *GeoDB

	// Logger is the log.Logger used for logging.
	// The default log will be used printing to os.Stdout with "pirsch" in its prefix in case it is not set.
	Logger *log.Logger
}

TrackerConfig is the optional configuration for the Tracker.

type UTMCampaignStats

type UTMCampaignStats struct {
	MetaStats
	UTMCampaign string `db:"utm_campaign" json:"utm_campaign"`
}

UTMCampaignStats is the result type for utm campaign statistics.

type UTMContentStats

type UTMContentStats struct {
	MetaStats
	UTMContent string `db:"utm_content" json:"utm_content"`
}

UTMContentStats is the result type for utm content statistics.

type UTMMediumStats

type UTMMediumStats struct {
	MetaStats
	UTMMedium string `db:"utm_medium" json:"utm_medium"`
}

UTMMediumStats is the result type for utm medium statistics.

type UTMSourceStats

type UTMSourceStats struct {
	MetaStats
	UTMSource string `db:"utm_source" json:"utm_source"`
}

UTMSourceStats is the result type for utm source statistics.

type UTMTermStats

type UTMTermStats struct {
	MetaStats
	UTMTerm string `db:"utm_term" json:"utm_term"`
}

UTMTermStats is the result type for utm term statistics.

type UserAgent

type UserAgent struct {
	// Browser is the browser name.
	Browser string

	// BrowserVersion is the browser (non technical) version number.
	BrowserVersion string

	// OS is the operating system.
	OS string

	// OSVersion is the operating system version number.
	OSVersion string
}

UserAgent contains information extracted from the User-Agent header.

func ParseUserAgent

func ParseUserAgent(ua string) UserAgent

ParseUserAgent parses given User-Agent header and returns the extracted information. This just supports major browsers and operating systems, we don't care about browsers and OSes that have no market share, unless you prove us wrong.

func (*UserAgent) IsDesktop

func (ua *UserAgent) IsDesktop() bool

IsDesktop returns true if the user agent is a desktop device.

func (*UserAgent) IsMobile

func (ua *UserAgent) IsMobile() bool

IsMobile returns true if the user agent is a mobile device.

type VisitorHourStats

type VisitorHourStats struct {
	Hour     int `json:"hour"`
	Visitors int `json:"visitors"`
}

VisitorHourStats is the result type for visitor statistics grouped by time of day.

type VisitorStats

type VisitorStats struct {
	Day        time.Time `json:"day"`
	Visitors   int       `json:"visitors"`
	Views      int       `json:"views"`
	Sessions   int       `json:"sessions"`
	Bounces    int       `json:"bounces"`
	BounceRate float64   `db:"bounce_rate" json:"bounce_rate"`
}

VisitorStats is the result type for visitor statistics.

Directories

Path Synopsis
demos

Jump to

Keyboard shortcuts

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