analytics

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: May 6, 2026 License: Apache-2.0 Imports: 18 Imported by: 0

Documentation

Overview

Package analytics implements the FUS telemetry pipeline for the TeamCity CLI.

Index

Constants

View Source
const (
	EventInvoked  = "invoked"
	EventExecuted = "executed"

	EventLoginCompleted = "login.completed"
	EventLoginAbandoned = "login.abandoned"
	EventTokenLoaded    = "token.loaded"

	EventStarted       = "started"
	EventWatchFinished = "watch.finished"
	EventLogViewed     = "log.viewed"
	EventTestsViewed   = "tests.viewed"
	EventDiffViewed    = "diff.viewed"

	EventTerminalClosed = "terminal.closed"
	EventExecFinished   = "exec.finished"
	EventStateChanged   = "state.changed"

	EventValidated = "validated"
	EventCreated   = "created"
	EventSynced    = "synced"

	EventManaged = "managed"

	EventLinked = "linked"
)
View Source
const (
	WorkspaceSourceFlag        = "flag"
	WorkspaceSourceAuto        = "auto"
	WorkspaceSourceInteractive = "interactive"
)
View Source
const (
	SourceHuman     = "human"
	SourceAgent     = "agent"
	SourceCI        = "ci"
	SourceBuildStep = "build_step"
)
View Source
const (
	CINone          = "none"
	CIOther         = "other"
	CIGitHubActions = "github_actions"
	CIGitLab        = "gitlab"
	CIJenkins       = "jenkins"
	CICircleCI      = "circleci"
	CIBuildkite     = "buildkite"
	CIAzure         = "azure"
	CITravis        = "travis"
	CITeamCity      = "teamcity"
)
View Source
const (
	AuthSourceKeyring         = "keyring"
	AuthSourceEnv             = "env"
	AuthSourceBuildProperties = "build_properties"
	AuthSourceGuest           = "guest"
	AuthSourceNone            = "none"
)
View Source
const (
	AuthMethodToken = "token"
	AuthMethodGuest = "guest"
)
View Source
const (
	AuthStepServer = "server"
	AuthStepToken  = "token"
	AuthStepVerify = "verify"
)
View Source
const (
	ServerTypeCloud  = "cloud"
	ServerTypeOnPrem = "on_prem"
)
View Source
const (
	ErrorAuth       = "auth"
	ErrorPermission = "permission"
	ErrorNotFound   = "not_found"
	ErrorNetwork    = "network"
	ErrorValidation = "validation"
	ErrorReadOnly   = "read_only"
	ErrorInternal   = "internal"
	ErrorNone       = "none"
)
View Source
const (
	BuildStatusSuccess  = "success"
	BuildStatusFailure  = "failure"
	BuildStatusError    = "error"
	BuildStatusCanceled = "canceled"
)
View Source
const (
	LogModeFull   = "full"
	LogModeFailed = "failed"
	LogModeRaw    = "raw"
	LogModeFollow = "follow"
)
View Source
const (
	TestsFilterAll    = "all"
	TestsFilterFailed = "failed"
	TestsFilterMuted  = "muted"
)
View Source
const (
	AgentActionEnable      = "enable"
	AgentActionDisable     = "disable"
	AgentActionAuthorize   = "authorize"
	AgentActionDeauthorize = "deauthorize"
	AgentActionMove        = "move"
	AgentActionReboot      = "reboot"
)
View Source
const (
	AgentExitUser         = "user"
	AgentExitTimeout      = "timeout"
	AgentExitDisconnected = "disconnected"
	AgentExitError        = "error"
)
View Source
const (
	PipelineActionPush = "push"
	PipelineActionPull = "pull"
)
View Source
const (
	SkillActionInstall = "install"
	SkillActionUpdate  = "update"
	SkillActionRemove  = "remove"
)
View Source
const (
	SkillScopeGlobal  = "global"
	SkillScopeProject = "project"
)
View Source
const (
	EnvAnalytics  = "TEAMCITY_ANALYTICS"
	EnvDoNotTrack = "DO_NOT_TRACK"
)
View Source
const (
	ConfigKey      = "analytics"
	NoticeShownKey = "analytics_notice_shown"
)
View Source
const (
	ProductCode     = "TCX"
	RecorderID      = "TCX"
	RecorderVersion = 1
	SchemeVersion   = "1"
)
View Source
const (
	GroupSession   = "teamcity.cli.session"
	GroupCommand   = "teamcity.cli.command"
	GroupAPI       = "teamcity.cli.api"
	GroupAuth      = "teamcity.cli.auth"
	GroupBuild     = "teamcity.cli.build"
	GroupAgent     = "teamcity.cli.agent"
	GroupPipeline  = "teamcity.cli.pipeline"
	GroupSkill     = "teamcity.cli.skill"
	GroupWorkspace = "teamcity.cli.workspace"
)
View Source
const AIAgentNone = "none"
View Source
const NoticeText = `` /* 267-byte string literal not displayed */
View Source
const Salt = "tcx-fus-v1"

Salt is the per-product anonymization namespace baked into the binary (CDN config doesn't carry one); a namespace separator, not a secret, but changing it invalidates longitudinal hash correlation.

View Source
const SessionWindow = 30 * time.Minute

Variables

View Source
var Scheme = &fus.Scheme{
	Version: SchemeVersion,
	Rules: &fus.SchemeRules{
		Enums: map[string][]string{
			enumBoolean:     {"true", "false"},
			enumOS:          {"darwin", "linux", "windows", "freebsd", "other"},
			enumArch:        {"amd64", "arm64", "386", "other"},
			enumServerType:  {"cloud", "on_prem"},
			enumCISystem:    {"github_actions", "gitlab", "jenkins", "circleci", "buildkite", "azure", "travis", "teamcity", "other", "none"},
			enumAuthSource:  {"keyring", "env", "build_properties", "guest", "none"},
			enumAIAgent:     allAIAgents(),
			enumSource:      {"human", "agent", "ci", "build_step"},
			enumExitCode:    {"0", "1", "2"},
			enumErrorType:   {"auth", "permission", "not_found", "network", "validation", "read_only", "internal", "none"},
			enumHTTPMethod:  {"GET", "POST", "PUT", "DELETE", "PATCH"},
			enumAPIResource: {"builds", "build_types", "projects", "agents", "users", "vcs", "queue", "tests", "problems", "changes", "pipelines", "cloud", "server", "other"},
			enumCommand:     allCommands(),
			enumSkillAgent:  skillAgentEnum(),
		},
		Regexps: map[string]string{
			regexpUUID:          `[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}`,
			regexpSemver:        `\d+\.\d+\.\d+(?:-[0-9a-zA-Z.-]+)?`,
			regexpServerVersion: `\d{4}\.\d{1,2}(?:\.\d+)?`,
			regexpInteger:       `\d+`,
		},
	},
	Groups: []fus.GroupSchema{
		sessionGroup(),
		commandGroup(),
		apiGroup(),
		authGroup(),
		buildGroup(),
		agentGroup(),
		pipelineGroup(),
		skillGroup(),
		workspaceGroup(),
	},
}

Scheme is the canonical FUS scheme; consumed at runtime and serialized to schema.json for AP registration.

Functions

func APIResource

func APIResource(endpoint string) string

APIResource maps a `/app/rest/...` endpoint to a coarse resource bucket; unknown → "other".

func ClassifySource

func ClassifySource(env Environment) string

ClassifySource collapses environment context into the four-bucket source taxonomy.

func DataDir

func DataDir() (string, error)

DataDir returns ($XDG_CONFIG_HOME|~/.config)/tc/.analytics, creating it if missing.

func DetectAIAgent

func DetectAIAgent() string

func DetectCI

func DetectCI() string

DetectCI returns the wire-enum value for the surrounding CI system; teamcity wins over generic CI.

func LoadServerInfo

func LoadServerInfo(serverURL string) (version, serverType string)

LoadServerInfo returns the cached server version + type for serverURL; empty strings when unknown.

func NormalizeAIAgent

func NormalizeAIAgent(instillName string) string

NormalizeAIAgent maps an instill agent name to the wire enum; "" → none, unknown → other.

func NormalizeArch

func NormalizeArch(goarch string) string

func NormalizeCommand

func NormalizeCommand(path string) string

NormalizeCommand returns the wire-safe value for a cobra command path; unknown → "other".

func NormalizeHTTPMethod

func NormalizeHTTPMethod(method string) string

NormalizeHTTPMethod maps an HTTP method to the wire enum; unknown → GET.

func NormalizeOS

func NormalizeOS(goos string) string

func PrintFirstRunNotice

func PrintFirstRunNotice(errOut io.Writer, alreadyShown, optedOut, quiet, noInput bool) bool

PrintFirstRunNotice writes the one-time notice; suppressed when shown, opted out, quiet, or no-input.

func SampleEvents

func SampleEvents() []fus.LogEvent

SampleEvents returns one canonical event per (group, event_id) covering every declared field.

func SaveServerInfo

func SaveServerInfo(serverURL, version, serverType string) error

SaveServerInfo writes the version + type for serverURL, merging into any existing entries.

func SessionFilePath

func SessionFilePath() (string, error)

SessionFilePath returns the persisted application-session record path.

Types

type APIEvent

type APIEvent struct {
	Method     string
	Endpoint   string
	StatusCode int
	Paginated  bool
	Slurp      bool
	HadFields  bool
	HadInput   bool
}

APIEvent carries the api-invoked counter event; typed because raw endpoints need sanitization.

type Client

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

Client is nil-safe. Pass nil for "disabled" — every Track* method becomes a no-op.

func New

func New(cfg Config) *Client

New builds a Client; FUS logger boots lazily on first Track and noops on failure.

func (*Client) Close

func (c *Client) Close() error

func (*Client) Flush

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

func (*Client) SessionID

func (c *Client) SessionID() string

func (*Client) Track

func (c *Client) Track(group, eventID string, data map[string]any)

Track emits a counter event. Field names and values must match the scheme; TestLintScheme catches drift at test time.

func (*Client) TrackAPI

func (c *Client) TrackAPI(e APIEvent)

func (*Client) TrackCommand

func (c *Client) TrackCommand(e CommandEvent)

func (*Client) TrackSession

func (c *Client) TrackSession()

TrackSession emits the session.invoked state event once per new session.

type CommandEvent

type CommandEvent struct {
	Command        string
	HasJSON        bool
	HasGitContext  bool
	HasLinkContext bool
	FlagCount      int
	ExitCode       int
	DurationMS     int64
	ErrorType      string
}

CommandEvent carries the command-executed counter event; typed because exit code and error type need normalization.

type Config

type Config struct {
	Salt             string
	CLIVersion       string
	ServerVersion    string // YYYY.MM[.x]; omitted from session event when empty
	ServerType       string // "cloud" | "on_prem"; omitted when empty
	AuthSource       string
	HasLinkedProject bool
	Session          *Session
	Environment      Environment

	// Debug, when non-nil, receives one line per lifecycle event (boot, track, flush). Pass f.Printer.Debug to surface only with --verbose / --debug.
	Debug func(string, ...any)
}

type Environment

type Environment struct {
	OS       string
	Arch     string
	CISystem string
	AIAgent  string
}

func DetectEnvironment

func DetectEnvironment() Environment

type OptOutReason

type OptOutReason string
const (
	OptOutNone       OptOutReason = ""
	OptOutDoNotTrack OptOutReason = "DO_NOT_TRACK"
	OptOutEnv        OptOutReason = "TEAMCITY_ANALYTICS=0"
	OptOutConfig     OptOutReason = "config: analytics=false"
)

func IsEnabled

func IsEnabled(configEnabled bool) (bool, OptOutReason)

IsEnabled reports whether analytics tracking is on; precedence: DO_NOT_TRACK > TEAMCITY_ANALYTICS > config > on.

type SchemeFinding

type SchemeFinding struct {
	Group string
	Event string
	Field string // empty when the diagnostic is on event.id
	Got   string // a "validation.*" sentinel
}

SchemeFinding is a single client-side-validation diagnostic against a sample event.

func LintScheme

func LintScheme() ([]SchemeFinding, error)

LintScheme runs every SampleEvents entry through the Scheme validator and returns any sentinels emitted.

func (SchemeFinding) String

func (f SchemeFinding) String() string

type ServerInfo

type ServerInfo struct {
	Version string `json:"version,omitempty"`
	Type    string `json:"type,omitempty"`
}

ServerInfo is the telemetry-only cache of TC server context, keyed by server URL. Lives alongside the FUS buffer in DataDir so users can wipe all telemetry state in one shot.

type Session

type Session struct {
	ID         string    `json:"id"`
	LastActive time.Time `json:"last_active"`
	IsNew      bool      `json:"-"`
}

func LoadOrCreateSession

func LoadOrCreateSession(now time.Time) (*Session, error)

LoadOrCreateSession reads or rotates the application session file at ~/.config/tc/.session.

Jump to

Keyboard shortcuts

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