Documentation
¶
Index ¶
- Constants
- func Anonymize(salt []byte, value string) string
- func ComputeBucket(deviceID string) int
- func EnumExpr(values ...string) string
- func EnumRefExpr(ref string) string
- func GetOrCreateDeviceID(dataDir string) (string, error)
- func RangeExpr(from, to int) string
- func RangeRefExpr(ref string) string
- func RegexpExpr(pattern string) string
- func RegexpRefExpr(ref string) string
- func WriteEventsSchemeJSON(es *EventsScheme, w io.Writer) error
- func WriteSchemeJSON(s *Scheme, w io.Writer) error
- type AnonymizedField
- type Anonymizer
- type Client
- type Definition
- type DropReason
- type ESEventDescriptor
- type ESFieldDescriptor
- type ESGroupDescriptor
- type ESRecorderDesc
- type ESRecorderFieldDesc
- type EventAction
- type EventDefinition
- type EventGroup
- type EventsScheme
- type FUSConfig
- type FieldDefinition
- type GroupDefinition
- type GroupSchema
- type GroupType
- type IntRange
- type LogEvent
- type Logger
- type LoggerOption
- type OnDropFunc
- type Recorder
- type RecorderConfig
- type RegionCode
- type Report
- type Scheme
- type SchemeRange
- type SchemeRules
- type Validator
Constants ¶
const AnonymizedValueRegex = `[0-9a-f]{64}(#[SC])+`
AnonymizedValueRegex matches the post-anonymization wire format: 64 hex chars + one-or-more #C/#S markers (mirrors the JVM HASH_PATTERN; coordinate any change with the metadata repo).
const HashRuleRef = "hash"
HashRuleRef is the metadata-global regexp rule name for anonymized (hashed) values. The events scheme references it as {regexp#hash} so the metadata pipeline applies its maintained global rule instead of an inline regexp (which reads as a false change on every diff).
const MaxDataFields = 10
MaxDataFields is the per-event data-field cap enforced by the FUS analytics UI. Track drops events that exceed this limit.
Variables ¶
This section is empty.
Functions ¶
func Anonymize ¶
Anonymize returns SHA-256(salt||value) as hex with a "#C" (client) suffix. Blank/whitespace values pass through unchanged.
func ComputeBucket ¶
ComputeBucket returns a value in [0, 256) derived from the device ID via SHA-256.
func EnumRefExpr ¶
EnumRefExpr returns an enum reference to the scheme-global Rules.Enums[ref].
func GetOrCreateDeviceID ¶
GetOrCreateDeviceID returns a persistent device ID from dataDir, generating one in ddMMyy+OSChar+UUID format if absent.
func RangeRefExpr ¶
RangeRefExpr returns a range reference to the scheme-global Rules.Ranges[ref].
func RegexpExpr ¶
RegexpExpr returns an inline regexp rule: "regexp:<pattern>". The pattern is anchored automatically by the validator.
func RegexpRefExpr ¶
RegexpRefExpr returns a regexp reference to the scheme-global Rules.Regexps[ref].
func WriteEventsSchemeJSON ¶
func WriteEventsSchemeJSON(es *EventsScheme, w io.Writer) error
WriteEventsSchemeJSON serializes an EventsScheme to w as indented JSON.
Types ¶
type AnonymizedField ¶
AnonymizedField declares which event_data fields should be hashed for a specific event ID within its group.
type Anonymizer ¶
type Anonymizer struct {
// contains filtered or unexported fields
}
Anonymizer hashes event_data fields declared in the scheme's anonymized_fields using Anonymize(salt, value).
func NewAnonymizer ¶
func NewAnonymizer(s *Scheme, salt []byte) *Anonymizer
NewAnonymizer builds an Anonymizer from the scheme's anonymized_fields.
func (*Anonymizer) AnonymizeEvent ¶
func (a *Anonymizer) AnonymizeEvent(e *LogEvent)
AnonymizeEvent hashes declared fields in e.Event.Data in place.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
type Definition ¶
type Definition struct {
Version string
Rules *SchemeRules // shared enum, regexp and range definitions
Groups []GroupDefinition
}
Definition declares groups, events and their fields, like Kotlin EventLogGroup.
func (*Definition) BuildEventsScheme ¶
func (d *Definition) BuildEventsScheme(cfg RecorderConfig, buildNumber string) (*EventsScheme, error)
BuildEventsScheme generates registration metadata from each event's own fields.
func (*Definition) BuildValidationScheme ¶
func (d *Definition) BuildValidationScheme() (*Scheme, error)
BuildValidationScheme merges event rules per group for an embedded fallback.
func (*Definition) Validate ¶
func (d *Definition) Validate() error
Validate checks declaration structure before either output is generated.
type DropReason ¶
type DropReason string
DropReason describes why an event was silently dropped by Track.
const ( DropTooManyFields DropReason = "too_many_data_fields" DropValidation DropReason = "validation_rejected" DropBufferError DropReason = "buffer_write_failed" )
type ESEventDescriptor ¶
type ESEventDescriptor struct {
Event string `json:"event"`
Fields []ESFieldDescriptor `json:"fields"`
Description string `json:"description,omitempty"`
}
type ESFieldDescriptor ¶
type ESGroupDescriptor ¶
type ESRecorderDesc ¶
type ESRecorderDesc struct {
RecorderID string `json:"recorderId"`
RecorderVersion int `json:"recorderVersion"`
IDs []ESRecorderFieldDesc `json:"ids"`
ClientData []ESRecorderFieldDesc `json:"clientData"`
SystemData []ESRecorderFieldDesc `json:"systemData"`
}
type ESRecorderFieldDesc ¶
type EventAction ¶
type EventDefinition ¶
type EventDefinition struct {
ID string
Description string
Fields []FieldDefinition
}
type EventGroup ¶
type EventGroup struct {
ID string `json:"id"`
Version int `json:"version"`
State bool `json:"state"`
}
func Group ¶
func Group(id string, version int) EventGroup
Group returns a counter EventGroup (State=false).
func StateGroup ¶
func StateGroup(id string, version int) EventGroup
StateGroup returns a state EventGroup (State=true).
type EventsScheme ¶
type EventsScheme struct {
BuildNumber string `json:"buildNumber,omitempty"`
Scheme []ESGroupDescriptor `json:"scheme"`
CommitHash string `json:"commitHash,omitempty"`
RecorderScheme []ESRecorderDesc `json:"recorderScheme,omitempty"`
}
EventsScheme is the product schema JSON that the FUS metadata team uses to generate metadata entries. Attach this to YT issues in the FUS project when requesting metadata changes.
func BuildEventsScheme
deprecated
func BuildEventsScheme(s *Scheme, cfg RecorderConfig, buildNumber string) (*EventsScheme, error)
Deprecated: use Definition.BuildEventsScheme; Scheme cannot preserve event-specific fields.
type FUSConfig ¶
type FUSConfig struct {
SendEndpoint string `json:"send_endpoint"`
MetadataEndpoint string `json:"metadata_endpoint,omitempty"`
Salt string `json:"salt"`
SaltRevision int `json:"salt_revision"`
FetchedAt int64 `json:"fetched_at"`
}
func FetchTestConfig ¶
func LoadOrFetchConfig ¶
func LoadOrFetchConfig(recorderID, productCode, productVersion, dataDir string, region RegionCode) (*FUSConfig, error)
LoadOrFetchConfig returns the public FUS config (send endpoint, options); salt may be empty — supply it via RecorderConfig.AnonymizationSalt.
type FieldDefinition ¶
type FieldDefinition struct {
Path string
Rules []string
DataType string // PRIMITIVE (default) or ARRAY
Anonymized bool
Description string
}
FieldDefinition describes a leaf; dotted paths represent nested objects.
type GroupDefinition ¶
type GroupDefinition struct {
ID string
Version int
Type GroupType
Description string
Events []EventDefinition
}
type GroupSchema ¶
type GroupSchema struct {
ID string `json:"id"`
Type GroupType `json:"type,omitempty"`
Builds []SchemeRange `json:"builds,omitempty"`
Versions []SchemeRange `json:"versions,omitempty"`
Rules *SchemeRules `json:"rules,omitempty"`
AnonymizedFields []AnonymizedField `json:"anonymized_fields,omitempty"`
}
GroupSchema is one EventGroupRemoteDescriptor: the per-group rules plus the build/version ranges that gate whether an event for this group is accepted.
type GroupType ¶
type GroupType string
GroupType distinguishes state collectors (per-device snapshots) from counter collectors (occurrence counts).
type LogEvent ¶
type LogEvent struct {
Recorder Recorder `json:"recorder"`
Product string `json:"product"`
IDs map[string]string `json:"ids"`
Internal bool `json:"internal"`
Time int64 `json:"time"`
Build string `json:"build"`
Session string `json:"session"`
Group EventGroup `json:"group"`
Bucket int `json:"bucket"`
Event EventAction `json:"event"`
SystemData map[string]any `json:"system_data,omitempty"`
ClientData map[string]any `json:"client_data,omitempty"`
}
LogEvent is a single LION v4 wire-format event.
type Logger ¶
type Logger struct {
// contains filtered or unexported fields
}
Logger buffers FUS events to disk and sends them on Flush.
func NewLogger ¶
func NewLogger(ctx context.Context, cfg RecorderConfig, opts ...LoggerOption) (*Logger, error)
func (*Logger) Close ¶
Close flushes all buffered events. Pass a context with a deadline to bound the flush duration; use context.Background() for an unbounded flush.
func (*Logger) Flush ¶
Flush sends all buffered events, merging consecutive duplicates. The mutex is held only during buffer I/O, not during the HTTP send, so Track calls are not blocked by network latency.
func (*Logger) Track ¶
func (l *Logger) Track(group EventGroup, eventID string, data map[string]any)
Track buffers an event to disk. Failures are silent unless an OnDrop callback is registered. Events with more than MaxDataFields entries are dropped.
Pipeline: raw event -> validator -> anonymizer -> escaper -> disk buffer.
type LoggerOption ¶
type LoggerOption func(*Logger)
func WithAnonymizer ¶
func WithAnonymizer(a *Anonymizer) LoggerOption
WithAnonymizer installs the field anonymizer. When set, event_data fields declared in the scheme's anonymized_fields are hashed before buffering.
func WithClient ¶
func WithClient(c *Client) LoggerOption
WithClient overrides the default HTTP client.
func WithFUSConfig ¶
func WithFUSConfig(cfg *FUSConfig) LoggerOption
WithFUSConfig overrides automatic config fetching.
func WithOnDrop ¶
func WithOnDrop(fn OnDropFunc) LoggerOption
WithOnDrop registers a callback invoked when Track silently drops an event.
func WithValidator ¶
func WithValidator(v *Validator) LoggerOption
WithValidator installs the client-side scheme validator. Required by NewLogger — every event is rewritten so that only scheme-approved keys and values reach the wire, and events whose group is registered but out of build/version range are dropped.
type OnDropFunc ¶
type OnDropFunc func(group, event string, reason DropReason)
OnDropFunc is called when Track silently drops an event.
type RecorderConfig ¶
type RecorderConfig struct {
// FUS recorder code (e.g., "TC").
RecorderID string
// Recorder protocol version.
RecorderVersion int
// Product identifier (e.g., "TCC" for TeamCity CLI).
ProductCode string
// Product version string (e.g., "0.5.0").
BuildVersion string
// Whether this is a JetBrains internal user.
Internal bool
// Directory for persisting device ID, buffer, and config cache.
DataDir string
// Overrides automatic device ID generation. If empty, one is generated.
DeviceID string
// CDN region for config endpoints. Defaults to RegionAll.
Region RegionCode
// AnonymizationSalt is the product-supplied salt used for SHA-256 device/session anonymization. Mirrors JVM FusClientConfig.anonymizationSalt. Takes priority over any salt in the public config.
AnonymizationSalt string
}
type RegionCode ¶
type RegionCode string
const ( RegionAll RegionCode = "ALL" RegionCN RegionCode = "CN" )
type Scheme ¶
type Scheme struct {
Version string `json:"version,omitempty"`
Rules *SchemeRules `json:"rules,omitempty"`
Groups []GroupSchema `json:"groups"`
}
Scheme mirrors the AP metadata JSON (EventGroupRemoteDescriptors on the JVM side). Each recorder publishes one of these in the Data Office metadata repo.
func FetchScheme ¶
FetchScheme downloads event group metadata from url and decodes it into a Scheme. The response format matches the JVM EventGroupRemoteDescriptors JSON published to the AP metadata CDN.
func LoadOrFetchScheme ¶
LoadOrFetchScheme returns the event group metadata for schemeURL, using a disk cache in dataDir with TTL-based freshness. When the remote is unreachable it falls back to the cached copy. This mirrors the JVM MetadataFileUpdater.getNewestFile flow.
schemeURL is the full metadata URL (use FUSConfig.SchemeURL to build it). Returns an error only when both remote and cache are unavailable.
func LoadSchemeFromFile ¶
LoadSchemeFromFile parses a scheme JSON file from disk.
type SchemeRange ¶
SchemeRange carries a build or version range used to gate a group. Empty From or To is treated as open-ended.
type SchemeRules ¶
type SchemeRules struct {
EventID []string `json:"event_id,omitempty"`
EventData map[string][]string `json:"event_data,omitempty"`
Enums map[string][]string `json:"enums,omitempty"`
Regexps map[string]string `json:"regexps,omitempty"`
Ranges map[string]IntRange `json:"ranges,omitempty"`
}
SchemeRules carries either group-local or global (scheme-level) rule bundles.
At group scope, EventID and EventData drive per-event validation. At scheme scope, Enums/Regexps/Ranges are global reference tables looked up by {enum#ref}/{regexp#ref}/{range#ref} expressions in group rules.
type Validator ¶
type Validator struct {
// contains filtered or unexported fields
}
Validator implements the client-side event validation contract from the JVM SensitiveDataValidator. It rewrites an event so that only scheme-approved keys and values reach the wire, replacing unknown / non-matching pieces with validator sentinels. If the event's group is registered but its build/version falls outside the declared ranges, the event is dropped.
Scope ported from JVM:
- event ID whitelist per group
- per-field rule set: enum, enum#ref, regexp, regexp#ref, range, range#ref
- build / version range filter per group
- sentinel replacement (third.party / validation.unmatched_rule / validation.undefined_rule / validation.incorrect_rule)
- pass-through for FUS system events (registered, invoked, …)
Not ported (unused by the TeamCity CLI spec):
- util#, expression, required:, default_value: rules
- dictionary rules beyond plain enum
- recursive validation of nested Map/List values in event_data
- system_data / client_data / ids validation pipelines
func NewValidator ¶
NewValidator compiles a Scheme into a ready-to-use validator. Rule expressions are parsed eagerly; a broken expression turns into an incorrectRuleStub so events still produce deterministic sentinels instead of crashing later.
func (*Validator) Validate ¶
Validate mirrors SensitiveDataValidator.validateEvent for LION v4. Returns (validated, false) when the event may be kept (possibly with sentinel replacement) and (zero, true) when the event must be dropped entirely — which only happens when the group is registered but its build/version filter rejects the event.