pug

package module
v0.0.1 Latest Latest
Warning

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

Go to latest
Published: Oct 31, 2026 License: MIT Imports: 33 Imported by: 0

README

Pug

github.com/pug-sh/sdk-go

Pug server-side SDK for Go: event tracking, profile identify, and analytics reads.

It authenticates with a private project API key (prv_…). Ingestion never fails, so a tracking call can't take down your request path.

Install

go get github.com/pug-sh/sdk-go

Requires Go 1.26 or newer.

Quick start

import (
	pug "github.com/pug-sh/sdk-go"
	commoneventsv1 "github.com/pug-sh/sdk-go/gen/common/events/v1"
	insightsv1 "github.com/pug-sh/sdk-go/gen/shared/insights/v1"
	"google.golang.org/protobuf/proto"
)

client, err := pug.New(pug.Options{
	APIKey:   os.Getenv("PUG_API_KEY"),
	Endpoint: "https://pug.example.com",
})
if err != nil {
	log.Fatal(err)
}
ctx := context.Background()

// Track an event. distinctID (who the event is for) comes first: a server has no ambient user.
// Properties are typed fields, in the same list as the options.
client.Track("user_42", "order.completed", pug.Float("amount", 49.0), pug.String("currency", "USD"))

// Well-known events get their properties validated against the event's schema...
client.Track("user_42", "feature_used", pug.String("featureId", "export"))
// ...or take the typed schema itself, so the fields are checked at compile time.
client.TrackWellKnown("user_42", &commoneventsv1.FeatureUsedProperties{FeatureId: proto.String("export")})

// Identify a profile. Like Track, it returns at once and never fails; identifies are queued and
// sent in batches.
client.Identify("user_42", pug.Email("ada@example.com"), pug.String("plan", "pro"))

// Reads return *pug.Error, which errors.Is matches to a sentinel per status code.
profile, err := client.Profiles.GetByExternalID(ctx, "user_42")
if errors.Is(err, pug.ErrNotFound) {
	// ...
}
for p, err := range client.Profiles.List(ctx, nil) {
	if err != nil {
		break
	}
	fmt.Println(p.GetExternalId())
}
trend, err := client.Insights.Query(ctx, &insightsv1.QueryRequest{ /* spec, time range, granularity */ })

// Drain on shutdown so no queued events or identifies are lost.
err = client.Close(ctx)

Behaviour

  • Ingestion never fails. Track, TrackWellKnown and Identify validate input client-side, log and drop anything invalid, and return nothing. They are non-blocking: background goroutines send events and identifies in batches by size (MaxSize) or interval (MaxWait). Identifies go out with BatchIdentify; a server that predates it gets one Identify call each.
  • Delivery is best-effort with retry. A transient send failure keeps events queued and retries after MaxWait; a permanent one (a fixed set of client-error codes, plus any non-transport error) dead-letters them via OnError. Close drains and reports anything still undelivered through OnError, which covers both events and identifies.
  • Reads are request/response and return errors (*pug.Error): they run in your control flow, so you own retry. They are not auto-retried. Your ctx deadline bounds them; without one, Timeout (10s) does.
  • Well-known events have typed, validated properties; any other kind is accepted as a custom event with loose properties.
  • Warnings and errors go to log/slog (slog.Default() unless you pass a Logger).

API

pug.New(pug.Options)
Option Type Default Description
APIKey string none Required. Private project key (prv_…).
Endpoint string hosted endpoint Pug server origin.
Batch pug.BatchConfig see below Ingestion buffers, one each for events and identifies: MaxSize (100, capped at 1000), MaxWait (5s), MaxQueueSize (10,000).
OnError pug.OnError none Dead-letter hook for queued events and identifies that couldn't be delivered.
Logger *slog.Logger slog.Default() Receives the SDK's warnings and errors.
HTTPClient *http.Client default transport Sends the requests.
Timeout time.Duration 10s Bounds each request whose context has no deadline.
pug.New(pug.Options{
	APIKey: apiKey, // required, prv_…
	Batch:  pug.BatchConfig{MaxSize: 100, MaxWait: 5 * time.Second, MaxQueueSize: 10_000},
	OnError: func(err error, lost pug.Undelivered) {
		// dead-letter sink for lost.Events and lost.Identifies; err matches pug.ErrQueueOverflow
		// or pug.ErrClosed, or is a *pug.Error for a failed send, e.g. errors.Is(err, pug.ErrUnauthenticated)
	},
})

OnError may run on the goroutine that called Track or Identify or on a background sender, so it must be safe for concurrent use, return promptly, and not call Flush or Close.

Ingestion (never fails)
  • client.Track(distinctID, kind, opts...): enqueue an event; opts holds its property fields, Properties maps and settings. Non-blocking.
  • client.TrackWellKnown(distinctID, event, opts...): enqueue a well-known event from its typed message (e.g. &commoneventsv1.PurchaseProperties{...}); the kind comes from the schema, and fields or Properties in opts ride along as custom properties.
  • client.Identify(externalID, opts...): queue a create-or-update of a profile; opts holds its trait fields, named traits, Traits maps and settings. Non-blocking.
  • client.Flush(ctx): send the queued events and identifies now.
  • client.Close(ctx): drain and shut down; call on graceful exit so nothing queued is lost. Events and identifies still undelivered when ctx ends are reported to OnError.

Properties and traits are typed fields, passed in the same list as the call's options:

Field Event property Trait
pug.String(key, v) string string
pug.Int(key, v) (any integer type) int number
pug.Float(key, v) double number
pug.Bool(key, v) bool bool
pug.Time(key, v) timestamp RFC 3339 string
pug.Duration(key, v) duration string, e.g. "1.5s" the same string
pug.Any(key, v) mapped by Go type (table below) JSON

When keys are only known at run time, pass a pug.Properties map to Track or a pug.Traits map to Identify; maps and fields mix freely, and a key set twice in one call takes the later value.

The kind is a pug.Kind. A string literal converts on its own, and a kind held in a variable needs pug.Kind(name), so a distinct ID passed where the kind belongs fails to compile.

Identify also takes named traits, which write the keys Pug's dashboard reads. They only compile in Identify, and an empty value is omitted:

Named trait Key
pug.Name(v) name
pug.FirstName(v) firstName
pug.LastName(v) lastName
pug.Email(v) email
pug.Avatar(v) avatar (the dashboard shows only an absolute https URL)

A NaN or ±Inf trait is dropped with a warning, and the rest of the identify still goes out.

Track options: pug.WithTimestamp(t), pug.WithSessionID(id) (overrides the per-client session; it must be a UUID, or it's ignored with a warning), pug.WithLocation(loc) (the visitor's location, see below). Identify options: pug.WithAnonymousID(id) (must start with anon-; triggers anon→identified merge), pug.WithDeviceID(id).

All options, fields and maps included, are optional and can go in any order. A map[string]any needs converting, as pug.Properties(m). A wrapper that takes its own props and opts ...pug.TrackOption forwards them as append([]pug.TrackOption{props}, opts...)....

For a well-known kind, Track's properties are keyed by the schema fields' JSON names (productId, not product_id) and must match their types; a field of the wrong type drops the event with an error. A key that is a field's proto name (product_id) doesn't set the field: it is sent as a custom property with a warning naming the JSON name, and if the field is required the event is dropped. pug.Any values and pug.Properties map by Go type:

Go value Sent as
string, bool string, bool
integers int (a uint64 past MaxInt64 is dropped)
float32, float64 double (NaN and ±Inf are dropped)
json.Number int when it has no fraction, else double
time.Time, *timestamppb.Timestamp timestamp
time.Duration, *durationpb.Duration duration string, e.g. "1.5s"
encoding.TextMarshaler its text
other maps, slices, structs JSON string
nil omitted

Strings are capped at 1024 bytes (truncated with a warning). Decode JSON request bodies with json.Decoder.UseNumber to keep whole numbers ints.

Pug only derives geo from CDN headers on browser (public-key) requests. This SDK uses a private key, so the server adds no geo of its own. Without a location, an event has no geo at all:

client.Track("user-123", "checkout_completed", pug.String("plan", "pro"),
	pug.WithLocation(pug.Location{Country: "DE", City: "Berlin"}),
)

Location fields: Continent, Country, Region, City, PostalCode, MetroCode, Timezone, and Coordinates (a latitude/longitude pair). Country must be an ISO 3166-1 alpha-2 code (case and surrounding spaces are normalized). Empty strings are omitted silently. A field that looks like a mistake (an unknown country, a coordinate out of range) is dropped with a warning and the rest is still sent. If nothing is usable the event goes out with no geo.

Reads (return *pug.Error)

These run in your control flow:

  • client.Profiles: Get, GetByExternalID, Delete, List (an auto-paginating iter.Seq2).
  • client.Activity: Feed, EventExplorer, Heatmap, ProfileSessions, ProfileStats, FilterSchema, PropertyValues.
  • client.Insights: Query, SegmentUsers, FilterSchema, PropertyValues.

Requests and responses are the generated protobuf types under gen/ (github.com/pug-sh/sdk-go/gen/shared/insights/v1, .../shared/activity/v1, .../shared/profiles/v1, .../common/v1).

Reads leave out traffic tagged as a bot at ingest unless you ask for it: pass pug.IncludeBots() to Profiles.Get and GetByExternalID, or set IncludeBots on the request.

Errors normalize to *pug.Error, which carries the underlying Connect Code and wraps the cause. errors.Is matches it to the sentinel for its code (pug.ErrNotFound, pug.ErrUnauthenticated, pug.ErrUnavailable and so on, one per Connect code):

if errors.Is(err, pug.ErrNotFound) {
	// ...
}
var perr *pug.Error
if errors.As(err, &perr) {
	log.Println(perr.Code, perr.Message)
}

Contributing

See docs/development.md for building, testing, and how the generated code and the well-known event catalog are maintained.

License

MIT

Documentation

Overview

Package pug is the Pug server-side SDK for Go: event tracking, profile identify, and analytics reads.

A Client authenticates with a private project API key (prv_…). Ingestion never fails: Client.Track, Client.TrackWellKnown and Client.Identify validate their input, log and drop anything invalid, and hand events and identifies to background senders that batch them, so a tracking call can't take down a request path. Properties and traits are typed fields such as String and Int, passed in the same list as the call's options. Anything that can't be delivered is reported to Options.OnError.

Reads (Client.Profiles, Client.Activity and Client.Insights) run in the caller's control flow: they return errors of type *Error and are never retried. errors.Is matches an *Error to the sentinel for its status code, such as ErrNotFound.

Call Client.Close on shutdown so queued events and identifies are not lost.

Example
package main

import (
	"context"
	"fmt"
	"log"
	"os"

	"google.golang.org/protobuf/proto"

	pug "github.com/pug-sh/sdk-go"
	commoneventsv1 "github.com/pug-sh/sdk-go/gen/common/events/v1"
)

func main() {
	client, err := pug.New(pug.Options{
		APIKey:   os.Getenv("PUG_API_KEY"),
		Endpoint: "https://pug.example.com",
	})
	if err != nil {
		log.Fatal(err)
	}
	ctx := context.Background()

	client.Track("user_42", "order.completed", pug.Float("amount", 49.0), pug.String("currency", "USD"))
	client.TrackWellKnown("user_42", &commoneventsv1.FeatureUsedProperties{FeatureId: proto.String("export")})
	client.Identify("user_42", pug.Email("ada@example.com"), pug.String("plan", "pro"))

	profile, err := client.Profiles.GetByExternalID(ctx, "user_42")
	if err != nil {
		log.Print(err)
	}
	fmt.Println(profile.GetId())

	if err := client.Close(ctx); err != nil {
		log.Print(err)
	}
}

Index

Examples

Constants

View Source
const Version = "0.0.1"

Version is the SDK version, sent with every event as the $sdkVersion auto-property.

Variables

View Source
var (
	// ErrClosed is reported to OnError for events and identifies that arrived after Close or
	// were still undelivered when it finished.
	ErrClosed = ingest.ErrClosed
	// ErrQueueOverflow is reported to OnError for the oldest events or identifies, dropped to
	// make room when their queue is full.
	ErrQueueOverflow = ingest.ErrQueueOverflow
)
View Source
var (
	ErrCanceled           error = codeError(connect.CodeCanceled)
	ErrUnknown            error = codeError(connect.CodeUnknown)
	ErrInvalidArgument    error = codeError(connect.CodeInvalidArgument)
	ErrDeadlineExceeded   error = codeError(connect.CodeDeadlineExceeded)
	ErrNotFound           error = codeError(connect.CodeNotFound)
	ErrAlreadyExists      error = codeError(connect.CodeAlreadyExists)
	ErrPermissionDenied   error = codeError(connect.CodePermissionDenied)
	ErrResourceExhausted  error = codeError(connect.CodeResourceExhausted)
	ErrFailedPrecondition error = codeError(connect.CodeFailedPrecondition)
	ErrAborted            error = codeError(connect.CodeAborted)
	ErrOutOfRange         error = codeError(connect.CodeOutOfRange)
	ErrUnimplemented      error = codeError(connect.CodeUnimplemented)
	ErrInternal           error = codeError(connect.CodeInternal)
	ErrUnavailable        error = codeError(connect.CodeUnavailable)
	ErrDataLoss           error = codeError(connect.CodeDataLoss)
	ErrUnauthenticated    error = codeError(connect.CodeUnauthenticated)
)

Sentinels for the Connect status codes, so errors.Is(err, ErrNotFound) checks an *Error's Code.

Functions

This section is empty.

Types

type ActivityClient

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

ActivityClient reads raw events and per-profile activity. Reads leave out traffic tagged as a bot at ingest unless the request sets include_bots.

func (*ActivityClient) EventExplorer

EventExplorer returns a page of events across every profile in the project.

func (*ActivityClient) Feed

Feed returns a page of one profile's events, merged anonymous events included.

func (*ActivityClient) FilterSchema

FilterSchema returns the event kinds and property keys available to filter by; req may be nil.

func (*ActivityClient) Heatmap

Heatmap returns one profile's per-day event counts.

func (*ActivityClient) ProfileSessions

ProfileSessions returns a page of one profile's sessions.

func (*ActivityClient) ProfileStats

ProfileStats returns one profile's aggregate statistics and latest device and location context.

func (*ActivityClient) PropertyValues

PropertyValues returns the distinct values seen for a property key.

type BatchConfig

type BatchConfig struct {
	// MaxSize is the buffered-event count that triggers a send, and the most events sent in
	// one request. Defaults to 100; capped at 1000.
	MaxSize int
	// MaxWait is the longest an event waits before its batch is sent, and the retry interval
	// after a transient failure. Defaults to 5s.
	MaxWait time.Duration
	// MaxQueueSize bounds the buffer: when it is full, the oldest event is dropped and
	// reported to OnError. Defaults to 10,000.
	MaxQueueSize int
}

BatchConfig tunes the ingestion buffers. Events and identifies each get a buffer with these settings. Zero fields take their defaults.

type Client

type Client struct {
	// Profiles reads and deletes profiles.
	Profiles *ProfilesClient
	// Activity reads raw events and per-profile activity.
	Activity *ActivityClient
	// Insights runs analytics queries.
	Insights *InsightsClient
	// contains filtered or unexported fields
}

Client is a Pug server-side client, safe for concurrent use. Ingestion is buffered and sent by a background goroutine, so call Client.Close on shutdown.

func New

func New(opts Options) (*Client, error)

New returns a Client. It fails only on unusable options: a missing, malformed or non-private API key, or an Endpoint that is not an absolute http(s) URL.

func (*Client) Close

func (c *Client) Close(ctx context.Context) error

Close drains both queues and stops their background senders; later Track and Identify calls are dropped with a warning. Events and identifies that cannot be delivered, including any left when ctx ends, are reported to OnError. It returns ctx's error if ctx ended before the drain finished.

Example
package main

import (
	"context"
	"log"
	"os"
	"time"

	pug "github.com/pug-sh/sdk-go"
)

func main() {
	client, _ := pug.New(pug.Options{
		APIKey: os.Getenv("PUG_API_KEY"),
		OnError: func(err error, lost pug.Undelivered) {
			log.Printf("dropping %d event(s) and %d identify(s): %v", len(lost.Events), len(lost.Identifies), err)
		},
	})

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	if err := client.Close(ctx); err != nil {
		log.Print(err)
	}
}

func (*Client) Flush

func (c *Client) Flush(ctx context.Context) error

Flush sends the queued events and identifies now. It returns once an attempt in progress and its own attempt have finished, or with ctx's error if ctx ends first. It does not guarantee empty queues: a transient failure keeps items queued for a later retry. Use Close to drain on shutdown.

func (*Client) Identify

func (c *Client) Identify(externalID string, opts ...IdentifyOption)

Identify queues a create-or-update of the profile for externalID and returns at once; a background goroutine sends identifies in batches with BatchIdentify, or with one Identify call each on a server that predates it. Its traits are fields (String, Int, …), named traits (Name, FirstName, LastName, Email, Avatar) and Traits maps, in the same list as the With… options, and are shallow-merged into the stored properties. It never fails: invalid input is logged and dropped, and an identify that can't be delivered is reported to OnError.

func (*Client) Track

func (c *Client) Track(distinctID string, kind Kind, opts ...TrackOption)

Track enqueues an event of kind for distinctID and returns at once; a background goroutine sends events in batches. Its properties are fields (String, Int, …) and Properties maps, in the same list as the With… options. It never fails: invalid input is logged and dropped.

For a well-known kind such as "purchase", properties are checked against the event's schema, keyed by the fields' JSON names ("productId"; "product_id" logs a warning), and other keys ride along as custom properties. Any other kind is a custom event with free-form properties. Client.TrackWellKnown takes the typed schema instead.

Example
package main

import (
	"context"
	"os"
	"time"

	pug "github.com/pug-sh/sdk-go"
)

func main() {
	client, _ := pug.New(pug.Options{APIKey: os.Getenv("PUG_API_KEY")})
	defer client.Close(context.Background())

	client.Track("user_123", "checkout_completed", pug.String("plan", "pro"),
		pug.WithLocation(pug.Location{Country: "DE", City: "Berlin"}),
		pug.WithTimestamp(time.Now().Add(-time.Minute)),
	)
}

func (*Client) TrackWellKnown

func (c *Client) TrackWellKnown(distinctID string, event proto.Message, opts ...TrackOption)

TrackWellKnown enqueues a well-known event from its typed properties message, such as &commoneventsv1.PurchaseProperties{...}; the kind comes from the message's schema. [Field]s and Properties among opts are sent as custom properties alongside the typed fields, except one keyed by a typed field's JSON name, which is dropped. Like Track, it never fails: invalid input is logged and dropped.

Example
package main

import (
	"context"
	"os"

	"google.golang.org/protobuf/proto"

	pug "github.com/pug-sh/sdk-go"
	commoneventsv1 "github.com/pug-sh/sdk-go/gen/common/events/v1"
)

func main() {
	client, _ := pug.New(pug.Options{APIKey: os.Getenv("PUG_API_KEY")})
	defer client.Close(context.Background())

	client.TrackWellKnown("user_42", &commoneventsv1.PurchaseProperties{
		Amount:   proto.Float64(49),
		Currency: proto.String("USD"),
		OrderId:  proto.String("ord_1"),
	}, pug.String("coupon", "FALL25"))
}

type Coordinates

type Coordinates struct {
	Latitude  float64
	Longitude float64
}

Coordinates are a position in decimal degrees. Latitude and longitude are sent together or not at all.

type Error

type Error struct {
	// Code is the Connect status code, or zero when the failure did not come from the RPC
	// layer.
	Code connect.Code
	// Message describes the failure, without the code.
	Message string
	// Err is the underlying error.
	Err error
}

Error is the error returned by the read methods and handed to OnError when a send fails. Ingestion never returns errors. Under errors.Is it matches the sentinel for its Code, such as ErrNotFound.

func (*Error) Error

func (e *Error) Error() string

func (*Error) Is

func (e *Error) Is(target error) bool

Is reports whether target is the sentinel for e's Code, such as ErrNotFound. An Error without a Code matches none.

func (*Error) Unwrap

func (e *Error) Unwrap() error

type Event

type Event = eventsv1.Event

Event is the wire form of a tracked event, as handed to OnError.

type Field

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

Field is one event property or profile trait, made by String, Int, Float, Bool, Time, Duration or Any. It goes in the same list as the call's other options, so the key sits next to its value and the value's type is fixed at compile time.

func Any

func Any(key string, value any) Field

Any is a property of any other type, mapped by its Go type as a Properties value is.

func Bool

func Bool(key string, value bool) Field

Bool is a boolean property.

func Duration

func Duration(key string, value time.Duration) Field

Duration is a duration property, sent as a string such as "1.5s".

func Float

func Float(key string, value float64) Field

Float is a floating-point property, sent as a double even when it is a whole number. NaN and ±Inf are dropped with a warning.

func Int

func Int[T integer](key string, value T) Field

Int is an integer property of any integer type. One past the int64 range is dropped with a warning.

func String

func String(key, value string) Field

String is a string property. One over 1024 bytes is truncated with a warning.

func Time

func Time(key string, value time.Time) Field

Time is a timestamp property.

type GetOption

type GetOption func(*getOptions)

GetOption customizes a single-profile lookup.

func IncludeBots

func IncludeBots() GetOption

IncludeBots counts traffic tagged as a bot at ingest in the profile's activity summary. It is left out by default.

type Identify

type Identify = sdkprofilesv1.IdentifyRequest

Identify is the wire form of a queued identify, as handed to OnError.

type IdentifyOption

type IdentifyOption interface {
	// contains filtered or unexported methods
}

IdentifyOption customizes one Client.Identify call: a Field, a named trait such as Email, the profile's Traits, or an option such as WithAnonymousID. Nil options are skipped.

func Avatar

func Avatar(value string) IdentifyOption

Avatar is the URL of the profile's picture, sent as the "avatar" trait. The dashboard shows only an absolute https URL.

func Email

func Email(value string) IdentifyOption

Email is the profile's email address, sent as the "email" trait.

func FirstName

func FirstName(value string) IdentifyOption

FirstName is the profile's first name, sent as the "firstName" trait. With LastName, the dashboard composes a display name when Name is unset.

func LastName

func LastName(value string) IdentifyOption

LastName is the profile's last name, sent as the "lastName" trait.

func Name

func Name(value string) IdentifyOption

Name is the profile's display name, sent as the "name" trait.

func WithAnonymousID

func WithAnonymousID(id string) IdentifyOption

WithAnonymousID names the SDK anonymous id (it must start with "anon-") whose profile is merged into the identified one.

func WithDeviceID

func WithDeviceID(id string) IdentifyOption

WithDeviceID assigns a device to the profile.

type InsightsClient

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

InsightsClient runs product-analytics queries. Queries leave out traffic tagged as a bot at ingest unless the spec sets include_bots.

func (*InsightsClient) FilterSchema

FilterSchema returns the event kinds and property keys available to filter and break down by; req may be nil.

func (*InsightsClient) PropertyValues

PropertyValues returns the observed values of an event or profile property.

func (*InsightsClient) Query

Query runs an insight (trends, segmentation, funnel, retention, user flow, top-K or map).

func (*InsightsClient) SegmentUsers

SegmentUsers returns a page of the distinct ids behind a set of events.

type Kind

type Kind string

Kind is an event's kind, such as "order.completed". An untyped string constant converts to it implicitly; a string variable needs Kind(s), so a distinct ID passed where the kind belongs fails to compile.

Example
package main

import (
	"context"
	"os"

	pug "github.com/pug-sh/sdk-go"
)

func main() {
	client, _ := pug.New(pug.Options{APIKey: os.Getenv("PUG_API_KEY")})
	defer client.Close(context.Background())

	kind := os.Getenv("CHECKOUT_EVENT") // a kind held in a variable needs the conversion
	client.Track("user_42", pug.Kind(kind), pug.Float("amount", 49))
}

type Location

type Location struct {
	Continent string
	// Country is an ISO 3166-1 alpha-2 code such as "DE". Case and surrounding spaces are
	// normalized.
	Country    string
	Region     string
	City       string
	PostalCode string
	MetroCode  string
	// Timezone is an IANA name such as "Europe/Berlin".
	Timezone    string
	Coordinates *Coordinates
}

Location is where the visitor is, for an event your backend sends on their behalf. Strings are trimmed and empty ones omitted. A field that looks like a mistake (an unknown country, a coordinate out of range) is dropped with a warning and the rest is still sent.

type OnError

type OnError func(err error, lost Undelivered)

OnError is a dead-letter hook for queued events and identifies that could not be delivered. err matches ErrQueueOverflow or ErrClosed under errors.Is, or is an *Error for a failed send. It runs on the goroutine that called Track or Identify or on a background sender, so it must be safe for concurrent use, return promptly, and not call Flush or Close.

type Options

type Options struct {
	// APIKey is the project's private API key (prv_…).
	APIKey string
	// Endpoint is the Pug server origin. Defaults to the hosted endpoint.
	Endpoint string
	// Batch tunes the ingestion buffer.
	Batch BatchConfig
	// OnError receives queued events and identifies that could not be delivered: a permanent
	// send failure, a queue overflow, or ones still undelivered at Close.
	OnError OnError
	// Logger receives the SDK's warnings and errors. Defaults to slog.Default().
	Logger *slog.Logger
	// HTTPClient sends the requests. Defaults to a client using http.DefaultTransport.
	HTTPClient *http.Client
	// Timeout bounds each request whose context has no deadline. Defaults to 10s.
	Timeout time.Duration
}

Options configures a Client. Only APIKey is required.

type ProfilesClient

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

ProfilesClient reads and deletes profiles. Reads leave out traffic tagged as a bot at ingest unless asked to include it.

func (*ProfilesClient) Delete

Delete erases the profile with the given id. Erasure completes asynchronously; the response carries the request id to track it by.

func (*ProfilesClient) Get

func (p *ProfilesClient) Get(ctx context.Context, id string, opts ...GetOption) (*profilesv1.Profile, error)

Get returns the profile with the given Pug profile id.

func (*ProfilesClient) GetByExternalID

func (p *ProfilesClient) GetByExternalID(ctx context.Context, externalID string, opts ...GetOption) (*profilesv1.Profile, error)

GetByExternalID returns the profile with the external id your application assigned it.

func (*ProfilesClient) List

List iterates over the profiles matching req, fetching pages as it goes; a nil req lists every profile. An error ends the iteration. The whole iteration runs under one request, so without a deadline on ctx it is bounded by Options.Timeout.

Example
package main

import (
	"context"
	"fmt"
	"log"
	"os"
	"time"

	pug "github.com/pug-sh/sdk-go"
)

func main() {
	client, _ := pug.New(pug.Options{APIKey: os.Getenv("PUG_API_KEY")})
	defer client.Close(context.Background())

	ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
	defer cancel()
	for profile, err := range client.Profiles.List(ctx, nil) {
		if err != nil {
			log.Print(err)
			break
		}
		fmt.Println(profile.GetExternalId())
	}
}

type Properties

type Properties map[string]any

Properties are an event's custom properties as a map, for keys only known at run time, passed to Client.Track or Client.TrackWellKnown among its options like a Field; given more than once, they are merged, later keys winning. Strings, booleans, integers and floats keep their type; time.Time becomes a timestamp and time.Duration a duration string like "1.5s"; json.Number is an integer when it has no fraction; a value implementing encoding.TextMarshaler is sent as its text; other maps, slices and structs are sent as JSON strings. Nil values are omitted, and a value that can't be represented (a func, NaN, a uint64 past the int64 range) is dropped with a warning.

type TrackOption

type TrackOption interface {
	// contains filtered or unexported methods
}

TrackOption customizes one tracked event: a Field, its Properties, or an option such as WithTimestamp. Nil options are skipped.

func WithLocation

func WithLocation(loc Location) TrackOption

WithLocation records the visitor's location. Pug derives geo only from browser requests, so an event sent with a private key carries the location set here or none at all.

func WithSessionID

func WithSessionID(id string) TrackOption

WithSessionID overrides the client's per-instance session id. It must be a UUID; an empty id keeps the default, and any other id is ignored with a warning.

func WithTimestamp

func WithTimestamp(t time.Time) TrackOption

WithTimestamp sets when the event happened; it defaults to now. A time before the Unix epoch or after year 9999 is almost certainly a unit mistake, so it is ignored with a warning.

type Traits

type Traits map[string]any

Traits are profile traits as a map, for keys only known at run time, passed to Client.Identify among its options like a Field and shallow-merged into the stored ones; given more than once, they are merged, later keys winning. They must be JSON-serializable.

type Undelivered

type Undelivered struct {
	Events     []*Event
	Identifies []*Identify
}

Undelivered is what one failure lost. Either slice may be empty.

Jump to

Keyboard shortcuts

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