Documentation
¶
Overview ¶
Package obsdash turns a forge project's own service metadata into observability dashboards.
The package has two layers, and the split is the point:
Spec (this file) is a backend-neutral description of WHAT to show: dashboards made of panels, each panel a query intent (signal, aggregate, predicates on OpenTelemetry attribute names). It names no ClickHouse column, no HyperDX field and no chart library. Build derives it from the project's services, rpcs, frontends and database. It is also serialized (deploy/observability/spec/, one file for the project and one per service — see ProcessPart) so a second renderer — the Reliant console, drawing with uPlot — can consume exactly the same model, through the release bundle, without parsing HyperDX JSON. The panel vocabulary and its validator are published as pkg/dashspec (aliased in dashspec.go), so every reader of a dashboard file judges it by the same rules.
RenderHyperDX (hyperdx.go) is one renderer over the Spec: it emits HyperDX v2 dashboard JSON for the file provisioner (local dev, operators) or for the HyperDX API (hosted).
Everything is keyed on OpenTelemetry names (service.name, deployment.environment.name, span.name, ...), the contract forge's runtime and KCL already settle, so no panel depends on how a given backend stores them.
Index ¶
- Constants
- func AlertDefaultAlertNames() []string
- func AlertDefaultIDs() []string
- func BindEnvID(expr, envID string) string
- func BuildParts(in Input) (ProjectPart, []ProcessPart)
- func DashboardFile(project string, d Dashboard) string
- func DashboardName(d Dashboard) string
- func IsBuiltinMetric(name string) bool
- func IsConsoleKind(k PanelKind) bool
- func IsPlatformExpr(expr string) bool
- func LooksLikeHyperDXDashboard(raw []byte) bool
- func LooksLikeSpecDashboard(raw []byte) bool
- func MarshalAlertDefaults(in AlertInput) ([]byte, error)
- func OverridePath(project string, d Dashboard) string
- func PlatformExpr(key string, off bool) string
- func ProcessDashboardID(name string) string
- func ProcessSpecFile(service string) string
- func ResolveAlertDefaultsFor(in AlertInput, env string, tuning map[string]AlertTuning, disabled []string) ([]AlertRule, []AlertSkip, error)
- func SavedSearchesFile(project, service string) string
- func ValidateAlertTuning(tuning map[string]AlertTuning) error
- func Write(projectDir string, in Input, cs *checksums.FileChecksums) ([]string, error)
- type Agg
- type AlertDefaultInfo
- type AlertDefaultsDoc
- type AlertInput
- type AlertParam
- type AlertRule
- type AlertService
- type AlertSkip
- type AlertTuning
- type Annotation
- type AnnotationSource
- type BundleDashboard
- type BundleDashboardSource
- type BundleFile
- type BundleSet
- type BundleSetInput
- type Dashboard
- type Filter
- type Fragments
- type FrontendFunnel
- type Funnel
- type FunnelBy
- type Group
- type HyperDXChart
- type HyperDXDashboard
- type HyperDXFilter
- type HyperDXNumFormat
- type HyperDXSavedSearch
- type HyperDXSelect
- type HyperDXTile
- type Identities
- type Input
- type Method
- type Op
- type Panel
- type PanelKind
- type Predicate
- type Problem
- type Process
- type ProcessPart
- type ProjectPart
- type Rendered
- type SavedSearch
- type Section
- type Series
- type Service
- type Signal
- type Spec
- type Thresholds
- type Unit
Constants ¶
const ( SeverityCritical = "critical" SeverityWarning = "warning" SeverityInfo = "info" )
Alert severities, the values of the `severity` label.
const ( PlatformDeployFailed = "deploy-failed" PlatformQuota = "observability-quota" // The issue alerts need the issue registry (new / regressed are state // transitions, and a spike is measured per issue), which the control plane // owns. They cover every issue the env has, browser or server. PlatformNewIssue = "new-issue" PlatformIssueRegressed = "issue-regressed" PlatformIssueSpike = "issue-spike" // PlatformReleaseRegressed fires when a promotion's after-window closes // and the release-health verdict is FAIL: the env's release_health.fail_on // findings, evaluated by the control plane with the same rule as // `forge obs check`. It stays silent on PASS and on INCONCLUSIVE. PlatformReleaseRegressed = "release-regressed" // PlatformServiceAnomaly fires when a service's request rate, error rate // or p95 leaves its seasonal baseline: the same hour of the week over the // previous 4 weeks (obsquery.EvalAnomalies, over the rpc.server.* metrics, // never spans). The control plane evaluates it; its limits (4 MADs, 50 // requests, a 1 point error-rate rise or a 1.5x p95 rise, 7 days of // history) are obsquery.DefaultAnomalyParams, not tunable params. The // alert is one per service and release (labels: service, env, release, // dedupe_key), with every signal that moved a finding in its why payload, // so a summary can quote no signal label. PlatformServiceAnomaly = "service-anomaly" )
Platform default ids: alerts the control plane raises from events it owns (a failed convergence, a quota state). They are tunable in forge.Alerts.defaults like any other id, and recorded in the shape's platform_alerts.
const ( GroupOverview = dashspec.GroupOverview GroupServices = dashspec.GroupServices GroupJobs = dashspec.GroupJobs GroupProduct = dashspec.GroupProduct GroupPlatform = dashspec.GroupPlatform GroupReleases = dashspec.GroupReleases GroupCustom = dashspec.GroupCustom Traces = dashspec.Traces Metrics = dashspec.Metrics Logs = dashspec.Logs KindNumber = dashspec.KindNumber KindLine = dashspec.KindLine KindTable = dashspec.KindTable KindSearch = dashspec.KindSearch KindBar = dashspec.KindBar KindHeatmap = dashspec.KindHeatmap KindSQL = dashspec.KindSQL KindIssues = dashspec.KindIssues KindSessions = dashspec.KindSessions KindFunnel = dashspec.KindFunnel KindText = dashspec.KindText FunnelBySession = dashspec.FunnelBySession FunnelByUser = dashspec.FunnelByUser DefaultFunnelWindow = dashspec.DefaultFunnelWindow DefaultFunnelBy = dashspec.DefaultFunnelBy AggCount = dashspec.AggCount AggCountDistinct = dashspec.AggCountDistinct AggSum = dashspec.AggSum AggAvg = dashspec.AggAvg AggMax = dashspec.AggMax AggQuantile = dashspec.AggQuantile AggLast = dashspec.AggLast AggRate = dashspec.AggRate AggIncrease = dashspec.AggIncrease AggMin = dashspec.AggMin UnitNone = dashspec.UnitNone UnitCount = dashspec.UnitCount UnitMillis = dashspec.UnitMillis UnitBytes = dashspec.UnitBytes UnitPercent = dashspec.UnitPercent UnitSeconds = dashspec.UnitSeconds OpEq = dashspec.OpEq OpNeq = dashspec.OpNeq OpIn = dashspec.OpIn OpNotIn = dashspec.OpNotIn OpPrefix = dashspec.OpPrefix OpMatch = dashspec.OpMatch OpExists = dashspec.OpExists OpGTE = dashspec.OpGTE FieldService = dashspec.FieldService FieldEnv = dashspec.FieldEnv AnnotationReleases = dashspec.AnnotationReleases SpecVersion = dashspec.SpecVersion )
The spec constants, from pkg/dashspec.
const ( // DashboardsDir is the project-relative directory mounted as HyperDX's // DASHBOARD_PROVISIONER_DIR. DashboardsDir = "deploy/observability/dashboards" // SpecDir holds the serialized Spec, the renderer-neutral model, as its // parts: ProjectSpecFile and one ProcessSpecFile per service (see // ProcessPart for why it is not one file). It sits beside the dashboards // directory, not in it, because the provisioner reads every *.json it // finds there. ReadSpec assembles it. SpecDir = "deploy/observability/spec" // ProjectSpecFile is the project's ProjectPart. ProjectSpecFile = SpecDir + "/project" + genSuffix // LegacySpecFile is the whole-project spec the parts replace. Write // retires it when pristine, as it does the whole-project // saved-searches_gen.ndjson, an unwritten *_gen.ndjson like any other. LegacySpecFile = "deploy/observability/dashboard-spec_gen.json" )
const ( SourceLogs = "Logs" SourceTraces = "Traces" SourceMetrics = "Metrics" )
Source names. The ClickStack local image pre-creates exactly these three sources (and Sessions); a tile names one of them in `config.source`.
The provisioner stores `source` verbatim, but the HyperDX UI resolves a tile's source by mongo id, and ids are random per database. So a rendered dashboard carries NAMES, and whatever delivers it resolves them: the local compose entrypoint rewrites names to ids before it provisions, and a hosted deliverer does the same through GET /api/v2/sources. Keeping names in the file keeps it identical across every database.
const ( KindServiceProc = "service" KindWorkerProc = "worker" KindOperatorProc = "operator" KindJobProc = "job" KindCronProc = "cron" )
Kinds a Process can have (the forge workload kinds that run something).
const AlertDefaultsFile = "deploy/observability/alert-defaults_gen.json"
AlertDefaultsFile is the project-relative file `forge generate` writes: the project metadata the default alert rules are derived from, plus the catalog of defaults with their tunable parameters. The per-service metadata is in each alertServicePart. `forge env shape` reads both back (ReadAlertInput) to resolve the defaults for one env (the SQL names the env, so a default is rendered per env, not once per project). It sits beside the dashboard spec, not in the dashboards directory the HyperDX provisioner scans.
const AlertDefaultsVersion = "forge.alert-defaults/v3"
AlertDefaultsVersion identifies the serialized shape of AlertDefaultsFile. v2 dropped input.services: each service's entry is its alertServicePart's Alert (see alertServicePart for why), and ReadAlertInput puts them back.
const CustomMetricsID = "custom-metrics"
CustomMetricsID is the id of the dashboard BuildCustomMetrics returns, so its file is "<project>-custom-metrics_gen.json".
const EnvIDPlaceholder = "{reliant_env_id:String}"
EnvIDPlaceholder stands for the env's id in a rule whose data is stamped with the id rather than the env's name: customer metadata, which the node agent labels from the namespace. The env id is not known when forge renders, so the SQL carries this token and whoever evaluates the rule binds it (BindEnvID here, for `forge obs alerts check`; the control plane for a deployed env).
const JobsID = "jobs"
JobsID is the id of the one dashboard every job and cron job shares, so its file is "<project>-jobs_gen.json".
const PartsVersion = "forge.dashboard-parts/v2"
PartsVersion identifies the shape of the files the Spec is written to disk as (ProjectPart, ProcessPart).
const PinnedHyperDX = "2.40.0"
PinnedHyperDX is the HyperDX / ClickStack version the rendered JSON is written and validated against. The provisioned-dashboard schema (DashboardWithoutIdSchema in @hyperdx/common-utils) is not a versioned public contract, so a bump of the ClickStack image is a bump of this constant AND a re-run of the schema gate (see hyperdx_schema_test.go).
const ReleasesID = "releases"
ReleasesID is the id of the dashboard BuildReleases returns, so its file is "<project>-releases_gen.json".
const WorkloadsID = "workloads"
WorkloadsID is the id of the dashboard BuildWorkloads returns, so its file is "<project>-workloads_gen.json".
Variables ¶
This section is empty.
Functions ¶
func AlertDefaultAlertNames ¶
func AlertDefaultAlertNames() []string
AlertDefaultAlertNames are the rule names the defaults take: a user rule may not reuse one.
func AlertDefaultIDs ¶
func AlertDefaultIDs() []string
AlertDefaultIDs are the ids a forge.Alerts.defaults map may tune.
func BuildParts ¶ added in v0.1.46
func BuildParts(in Input) (ProjectPart, []ProcessPart)
BuildParts derives the project's Spec as process parts, sorted by process identity. RPC-free workers and gateways retain their runtime/workload panels.
func DashboardFile ¶
DashboardFile is the file name of d inside the dashboards directory.
func DashboardName ¶
DashboardName is the HyperDX dashboard name for d: the provisioner upserts by name, so it must be stable and unique across the project.
func IsBuiltinMetric ¶
IsBuiltinMetric reports whether name is one of forge's own metrics (rpc.*, go.*, forge.*, a component's .calls/.errors/.duration). Those have purpose-built dashboards; the custom-metrics dashboard is for the rest.
func IsConsoleKind ¶ added in v0.1.46
IsConsoleKind is dashspec.IsConsoleKind.
func IsPlatformExpr ¶
IsPlatformExpr reports whether expr is a recorded platform default.
func LooksLikeHyperDXDashboard ¶
LooksLikeHyperDXDashboard is dashspec.LooksLikeHyperDXDashboard.
func LooksLikeSpecDashboard ¶
LooksLikeSpecDashboard is dashspec.LooksLikeSpecDashboard.
func MarshalAlertDefaults ¶
func MarshalAlertDefaults(in AlertInput) ([]byte, error)
MarshalAlertDefaults is the file's bytes: the catalog for in, with the services left to their alertServiceParts.
func OverridePath ¶
OverridePath is the file that, when present, replaces the generated dashboard d: forge neither writes nor refreshes its _gen twin. The file is the project's, and forge never touches it.
func PlatformExpr ¶
PlatformExpr is the expr a platform default is recorded under; key is "<id>" or "<id>:<level>". It is a real SELECT that returns no row, so a ClickHouse evaluator that does not know the marker finds nothing and never fires; the control plane recognizes the comment, binds the env id and evaluates the event itself. `off` records that the env disabled the default.
func ProcessDashboardID ¶ added in v1.0.9
ProcessDashboardID is the dashboard id of the process named name.
func ProcessSpecFile ¶ added in v1.0.0
ProcessSpecFile is the project-relative file of service's ProcessPart.
func ResolveAlertDefaultsFor ¶
func ResolveAlertDefaultsFor(in AlertInput, env string, tuning map[string]AlertTuning, disabled []string) ([]AlertRule, []AlertSkip, error)
ResolveAlertDefaultsFor is ResolveAlertDefaults for an env that opted out of the observability categories in disabled. A default that reads a disabled category's data has nothing to read, so it is left out and reported as skipped, not recorded as a rule that can only ever be empty.
A platform default (deploy-failed, observability-quota) is always recorded, because the control plane raises it from its own events: enabled, it is an entry carrying the env's `for` and labels; disabled, an entry marked off.
func SavedSearchesFile ¶
SavedSearchesFile is the project-relative file holding service's HyperDX saved searches, one JSON object per line, named like the service's dashboard. It lives in the dashboards directory (the one directory compose mounts) under an extension the dashboard provisioner ignores; the compose entrypoint upserts every *_gen.ndjson there, because the file provisioner has no saved-search path. One file per service, for the reason in ProcessPart.
func ValidateAlertTuning ¶
func ValidateAlertTuning(tuning map[string]AlertTuning) error
ValidateAlertTuning refuses a tuning that names an unknown default or an unknown parameter of one, so a typo is an error at render, not a default that silently keeps its old threshold.
Types ¶
type AlertDefaultInfo ¶
type AlertDefaultInfo struct {
ID string `json:"id"`
Alert string `json:"alert"`
Title string `json:"title"`
Severity string `json:"severity"`
For string `json:"for"`
Interval string `json:"interval"`
// Signal is where the default reads: metrics, traces, metadata (the node
// agent's customer metadata) or platform (the control plane's own events).
Signal string `json:"signal"`
// Requires names the observability category whose opt-out leaves the
// default nothing to read ("metadata"). Empty = always applicable.
Requires string `json:"requires,omitempty"`
// AlertNames are further rule names the default also takes, beyond Alert.
AlertNames []string `json:"alert_names,omitempty"`
Params []AlertParam `json:"params"`
}
AlertDefaultInfo is a default as the generated file records it.
type AlertDefaultsDoc ¶
type AlertDefaultsDoc struct {
Version string `json:"version"`
Input AlertInput `json:"input"`
Defaults []AlertDefaultInfo `json:"defaults"`
}
AlertDefaultsDoc is the serialized AlertDefaultsFile.
func AlertDefaults ¶
func AlertDefaults(in AlertInput) AlertDefaultsDoc
AlertDefaults is the catalog for the generated file: every default the input applies to, at its default parameters.
type AlertInput ¶
type AlertInput struct {
Project string `json:"project"`
// Services are the project's services that have at least one rpc. The
// generated file leaves them out (each is in its alertServicePart).
Services []AlertService `json:"services,omitempty"`
// FrontendServices are the service.names the project's web frontends'
// browser SDK reports (naming.FrontendServiceName: "<project>-<frontend>",
// what each otel_gen.ts bakes as SERVICE_NAME), empty when the project has
// no web frontend. The frontend defaults fire per service.name.
FrontendServices []string `json:"frontend_services,omitempty"`
// UptimeChecks are the names of the env's uptime checks (the release
// shape's uptime_checks). They are a fact about one env, not the project,
// so the generated file never records them: the resolver sets them per
// env. The uptime defaults apply only to an env that has checks, and read
// only those checks' series, so a check an env opts out of cannot alert.
UptimeChecks []string `json:"-"`
}
AlertInput is what the defaults are derived from.
func AlertInputOf ¶
func AlertInputOf(in Input) AlertInput
AlertInputOf derives the defaults' input from the same Input the dashboards are built from, so the two can never disagree about what a project has.
func ParseAlertDefaults ¶
func ParseAlertDefaults(b []byte) (AlertInput, error)
ParseAlertDefaults reads the generated file: the input without its services (ReadAlertInput adds them).
func ReadAlertInput ¶ added in v0.1.46
func ReadAlertInput(projectDir string) (in AlertInput, ok bool, err error)
ReadAlertInput reads the alert defaults' input forge generate last wrote under projectDir: AlertDefaultsFile, with each alertServicePart's Alert as its services. ok is false when there is no AlertDefaultsFile — a project that has not run `forge generate` since alerting landed has no defaults, which is not an error.
type AlertParam ¶
type AlertParam struct {
Name string `json:"name"`
Default float64 `json:"default"`
Doc string `json:"doc"`
}
AlertParam is one numeric knob of a default's query.
type AlertRule ¶
type AlertRule struct {
ID string
Alert string
Expr string
For string
Interval string
Labels map[string]string
Annotations map[string]string
}
AlertRule is one resolved default: a rule ready for an env's shape.
func ResolveAlertDefaults ¶
func ResolveAlertDefaults(in AlertInput, env string, tuning map[string]AlertTuning) ([]AlertRule, error)
ResolveAlertDefaults renders the defaults for one env, with the env's tuning applied. A default the env disables is left out. Rules come back sorted by alert name.
type AlertService ¶
AlertService is one Connect service the defaults watch. RPCService is the procedure prefix the RPC interceptors label metrics with: "<package>.<ProtoService>", the second segment of "/orders.v1.OrdersService/GetOrder".
type AlertSkip ¶
type AlertSkip struct{ ID, Reason string }
AlertSkip is a default left out of an env's rules, and why.
type AlertTuning ¶
type AlertTuning struct {
Enabled bool
Labels map[string]string
For string
Params map[string]float64
}
AlertTuning is how an env adjusts one default (forge.AlertDefault).
type AnnotationSource ¶
type AnnotationSource = dashspec.AnnotationSource
AnnotationSource is dashspec.AnnotationSource.
type BundleDashboard ¶
type BundleDashboard struct {
// Name is the file name without ".json", and without "_gen" for a
// generated one: the key a project file overrides by.
Name string
Source BundleDashboardSource
// Path is the file's path inside the bundle.
Path string
// Dashboard is the parsed content; Data is the exact bytes shipped.
Dashboard Dashboard
Data []byte
}
BundleDashboard is one file of the bundle's observability/dashboards/.
type BundleDashboardSource ¶
type BundleDashboardSource string
BundleDashboardSource says who authored a bundled dashboard.
const ( SourceGenerated BundleDashboardSource = "gen" SourceUser BundleDashboardSource = "user" )
The sources of a bundled dashboard.
type BundleFile ¶
BundleFile is a path and its bytes.
func BundleFiles ¶
func BundleFiles(s BundleSet) []BundleFile
BundleFiles returns the set as bundle files, in path order.
type BundleSet ¶
type BundleSet struct {
Dashboards []BundleDashboard
// MetricsSchema is the raw forge.metrics/v1 document, or nil.
MetricsSchema []byte
// Notes are things worth telling the person cutting the release (a
// HyperDX-only file that was not shipped).
Notes []string
}
BundleSet is everything the bundle carries under observability/.
func CollectBundleSet ¶
func CollectBundleSet(in BundleSetInput) (BundleSet, error)
CollectBundleSet assembles and validates the observability files of a bundle. It returns nothing for a project that has neither generated dashboards nor a metrics schema, and an error (a *ProblemsError for a bad dashboard file) when a file the project owns is not a valid dashboard.
type BundleSetInput ¶
type BundleSetInput struct {
// ProjectDir is the project root; the project's name is the one
// dashboard-spec_gen.json records.
ProjectDir string
// MetricsSchema is the raw metrics schema the build produced, or nil.
MetricsSchema []byte
// Resolved is the selected environment's pure assembly. Non-nil replaces
// disk generated dashboards, including stale process parts; owned overrides
// still apply through the same stable filename/ID path.
Resolved *Spec
}
BundleSetInput is what CollectBundleSet reads.
type Dashboard ¶
Dashboard is dashspec.Dashboard.
func BuildCustomMetrics ¶
BuildCustomMetrics turns a metrics schema into the "Custom metrics" dashboard: one section per project-declared metric, drawn by its type.
counter a rate, per second updowncounter the current value (last) gauge the current value (last) histogram p50, p95 and p99
A metric with enumerated attribute values is grouped by each such attribute (one panel per attribute) — the closed set is what makes a group-by safe, since the series count is bounded by the declaration. Attributes without an enumerated set are offered as dashboard filters, not group-bys, so a high-cardinality key never fans a panel out into hundreds of lines.
Deprecated metrics are omitted. It returns false when the schema declares nothing of the project's own.
func BuildJobs ¶ added in v1.0.9
BuildJobs is the "Jobs" dashboard: every job and cron job of the project in one place, instead of one dashboard per job that is empty between runs.
A run is read from the Job controller's Kubernetes events, so it needs the cluster collector and a deployed environment; a local forge env up draws it empty. A JOB is a forge process (obsdash.Process): the workloads that run one command, which an environment may name differently.
EVERY panel is a SQL panel that selects through jobResolverSQL. That is not a style choice. The console hands the dashboard's service selector to every declarative panel as ServiceName IN (...) and a panel cannot opt out. The telemetry a job leaves carries three different names (metrics the workload, logs the service.name, events the Job object's), so a declarative panel selects a different subset than its neighbours, or nothing. A SQL panel receives the selection only through the resolver, which turns it into jobs and then filters each source by the identity that source carries.
jobs must be non-empty; Build only calls it when the project has some.
func BuildReleases ¶
BuildReleases is the "Releases" dashboard: how each release behaved, side by side. Every panel splits one signal by service.version, so the version that replaced another is a new line next to it and a regression is the line that departs at the cut-over. The Reliant console draws the deploy markers on these charts (and on every other time-series chart) from the dashboard's releases annotation, which is declared on all of them by Build.
The comparison table is the before/after view: one row per version over the selected time range, so choosing a range that spans a deploy puts the old and the new version in adjacent rows.
func BuildWorkloads ¶
BuildWorkloads is the "Workloads" dashboard: what the platform knows about every workload without the workload instrumenting anything. CPU and memory against what the container requested and may use, restarts and why the container last exited, the image versions that ran, and the Kubernetes events (crash loops, failed pulls, evictions).
It reads node-derived telemetry, which only a deployed environment has: a `forge env up` stack draws these panels empty. The owning org and environment are stamped from namespace labels, never from the payload, so a workload cannot spoof what these panels show.
Every panel is a line, number or search panel: a table over metrics is not something the console's query engine runs, so the per-container images and versions table is the console's workload view, and the version history is drawn here as CPU by image tag.
type Fragments ¶ added in v1.0.0
type Fragments struct {
Frontends []string
FrontendServices []string `json:",omitempty"`
HasDatabase bool
Funnels []FrontendFunnel
}
Fragments holds only project-wide generation inputs. Per-service alert inputs live in separate parts, and dashboard RPC ownership comes from the rendered workloads (Process.RPCServices). Duplicating the service inventory here would make independent service additions change the same shared JSON; the merge driver keeps one side's certified render, losing the other addition.
type FrontendFunnel ¶ added in v0.1.46
FrontendFunnel is one declared funnel (forge.Funnel in KCL).
type HyperDXChart ¶
type HyperDXChart struct {
Name string `json:"name"`
Source string `json:"source"`
DisplayType string `json:"displayType"`
Select any `json:"select"` // []HyperDXSelect, or a column string for a search tile
Where string `json:"where"`
WhereLanguage string `json:"whereLanguage"`
GroupBy string `json:"groupBy,omitempty"`
Granularity string `json:"granularity,omitempty"`
SeriesReturn string `json:"seriesReturnType,omitempty"`
NumberFormat *HyperDXNumFormat `json:"numberFormat,omitempty"`
Align *bool `json:"alignDateRangeToGranularity,omitempty"`
}
HyperDXChart is a builder-style saved chart config.
type HyperDXDashboard ¶
type HyperDXDashboard struct {
Name string `json:"name"`
Tags []string `json:"tags"`
Tiles []HyperDXTile `json:"tiles"`
Filters []HyperDXFilter `json:"filters,omitempty"`
}
HyperDXDashboard is a dashboard in the shape the HyperDX provisioner and the v2 dashboards API accept (DashboardWithoutIdSchema).
type HyperDXFilter ¶
type HyperDXFilter struct {
ID string `json:"id"`
Type string `json:"type"`
Name string `json:"name"`
Expression string `json:"expression"`
Source string `json:"source"`
WhereLanguage string `json:"whereLanguage"`
}
HyperDXFilter is a QUERY_EXPRESSION dashboard filter: a dropdown whose selection is added to every tile's WHERE.
type HyperDXNumFormat ¶
type HyperDXNumFormat struct {
Output string `json:"output"`
Mantissa *int `json:"mantissa,omitempty"`
ThousandSeparated bool `json:"thousandSeparated,omitempty"`
Unit string `json:"unit,omitempty"`
}
HyperDXNumFormat mirrors NumberFormatSchema.
type HyperDXSavedSearch ¶
type HyperDXSavedSearch struct {
Name string `json:"name"`
Source string `json:"source"`
Select string `json:"select"`
Where string `json:"where"`
WhereLanguage string `json:"whereLanguage"`
OrderBy string `json:"orderBy"`
Tags []string `json:"tags"`
}
HyperDXSavedSearch is the body of POST /api/v2/saved-searches style creation; the file provisioner has no saved-search path, so it is rendered for the API deliverer and listed in the spec.
func RenderHyperDXSavedSearches ¶
func RenderHyperDXSavedSearches(sp Spec) ([]HyperDXSavedSearch, error)
RenderHyperDXSavedSearches renders the spec's saved searches in the shape of the HyperDX saved-search API.
type HyperDXSelect ¶
type HyperDXSelect struct {
AggFn string `json:"aggFn"`
Level float64 `json:"level,omitempty"`
ValueExpr string `json:"valueExpression"`
AggCondition string `json:"aggCondition,omitempty"`
AggCondLang string `json:"aggConditionLanguage,omitempty"`
Alias string `json:"alias,omitempty"`
MetricName string `json:"metricName,omitempty"`
MetricType string `json:"metricType,omitempty"`
NumberFormatP *HyperDXNumFormat `json:"numberFormat,omitempty"`
}
HyperDXSelect is one aggregate of a chart.
type HyperDXTile ¶
type HyperDXTile struct {
ID string `json:"id"`
X int `json:"x"`
Y int `json:"y"`
W int `json:"w"`
H int `json:"h"`
Config HyperDXChart `json:"config"`
}
HyperDXTile is one chart on the 24-column grid.
type Identities ¶ added in v1.0.0
type Identities struct {
ServiceNames []string
Workloads []string
// RPCServiceNames are the service.names of the processes that serve RPCs:
// the only ones an rpc.server.* panel can have data for.
RPCServiceNames []string
// CPULimitWorkloads and MemoryLimitWorkloads are the workloads that
// declare that limit: the only ones a *_limit_utilization panel can have
// data for.
CPULimitWorkloads []string
MemoryLimitWorkloads []string
}
Identities are the telemetry and workload names deployed processes run under: what the overview's panels are scoped to.
type Input ¶
type Input struct {
Project string
Services []Service
Processes []Process
Frontends []string
// FrontendServices, when set, are the service.names those frontends report
// (a frontend built from another repository bakes its own); empty derives
// each from the project and frontend name (naming.FrontendServiceName).
FrontendServices []string
// HasDatabase adds the database panels: true once the project has a
// migration, since the panels read spans the ORM's query hook emits.
HasDatabase bool
// Funnels are the declared product funnels. Each becomes one panel on the
// frontend dashboard, so they only matter when Frontends is non-empty.
Funnels []FrontendFunnel
// Deployed scopes the overview, together with Processes' own identities,
// when the per-process inventory is not being built: forge generate knows
// every environment's deployed service.names and workloads, but per-process
// parts are the selected environment's alone (built at bundle time, see
// ProcessPart). Without it a generate-time overview filtered on the
// no-deployed-process sentinel and drew nothing.
Deployed Identities
}
Input is what Build reads from the project.
type Process ¶ added in v1.0.0
type Process struct {
// Name is the forge workload name (the first, when several workloads run
// the same executable and command): "admin-api", never the rendered
// Kubernetes object name, the command line or a hash. It names the
// process's dashboard ("process-<name>").
Name string `json:"name"`
// Kind is the forge workload kind: service, worker, operator, job or
// cron. Empty is a service. Jobs and crons share one Jobs dashboard.
Kind string `json:"kind,omitempty"`
Binary string `json:"binary"`
Args []string `json:"args,omitempty"`
Root string `json:"root,omitempty"`
ServiceNames []string `json:"serviceNames"`
Workloads []string `json:"workloads"`
RPCServices []string `json:"rpcServices,omitempty"`
HasDatabase bool `json:"hasDatabase,omitempty"`
// CPULimit and MemoryLimit say the workload declares that resource limit,
// the only case the node agent's *_limit_utilization series exist.
CPULimit bool `json:"cpuLimit,omitempty"`
MemoryLimit bool `json:"memoryLimit,omitempty"`
// NodeMetadata says the process runs where the node agent delivers
// per-container metadata (a cluster or hosted runtime); a host or compose
// process has no saturation or restart series.
NodeMetadata bool `json:"nodeMetadata,omitempty"`
// ServesRPCDeclared is set for a Go process forge does not build (a sibling
// repository's, built by a ShellBuild): a service with a port is taken to
// serve RPCs, since forge cannot read its mounts.
ServesRPCDeclared bool `json:"servesRpcDeclared,omitempty"`
// NonGo is set for a process forge can tell is not a Go program of this
// project or its siblings (a third-party or Docker-built image): it has no
// Go runtime metrics and no RPC metrics to draw.
NonGo bool `json:"nonGo,omitempty"`
// Replaces are the names (dashboard ids minus "process-") this process
// was known by before dashboards were named for the workload.
Replaces []string `json:"replaces,omitempty"`
}
Process is a deployed executable and command/root, with the exact telemetry and workload identities it owns across environments. No RPC ownership is inferred from a package name, a workload name, or handler reach alone.
type ProcessPart ¶ added in v1.0.0
type ProcessPart struct {
Version string `json:"version"`
Process Process `json:"process"`
Dashboard Dashboard `json:"dashboard"`
SavedSearches []SavedSearch `json:"savedSearches"`
}
ProcessPart holds one deployed executable/role's dashboard and saved searches. Separate files keep unrelated process changes disjoint; RPC alert inputs are independent alert-service parts, never duplicated for each mounting process.
type ProjectPart ¶ added in v0.1.46
type ProjectPart struct {
// Input retains reusable generation fragments; selected-env assembly fills
// Processes from rendered KCL, never from stale disk process parts.
Input *Fragments `json:"input,omitempty"`
Version string `json:"version"`
Project string `json:"project"`
Overview Dashboard `json:"overview"`
Dashboards []Dashboard `json:"dashboards"`
}
ProjectPart is the part of the Spec that belongs to the project as a whole: the overview, which leads, and the dashboards that follow the services' (Workloads, Releases, the frontend's). See ProcessPart.
type Rendered ¶
Rendered is one output file: a name relative to the dashboards directory and its bytes.
func RenderHyperDX ¶
RenderHyperDX renders every dashboard of sp as one provisioner file each, named "<project>-<dashboard id>_gen.json".
func SortedFiles ¶
SortedFiles returns rs ordered by file name.
type SavedSearch ¶
type SavedSearch struct {
ID string `json:"id"`
Title string `json:"title"`
Signal Signal `json:"signal"`
Where []Predicate `json:"where"`
Columns []string `json:"columns,omitempty"`
}
SavedSearch is a named log search a service owner returns to.
type Service ¶
type Service struct {
// Name is the short service name used in file names and titles
// ("orders").
Name string
// Package is the proto package ("orders.v1"); ProtoService the proto
// service name ("OrdersService"). Together they give the procedure
// "orders.v1.OrdersService/GetOrder" the RPC interceptors name spans by.
Package string
ProtoService string
Methods []Method
}
Service is one Connect/gRPC service.
type Spec ¶
type Spec struct {
Version string `json:"version"`
Project string `json:"project"`
Dashboards []Dashboard `json:"dashboards"`
SavedSearches []SavedSearch `json:"savedSearches"`
}
Spec is everything the generator derives for one project.
func Assemble ¶ added in v0.1.46
func Assemble(project ProjectPart, processes []ProcessPart) Spec
Assemble is the Spec its parts make: the overview, then each service's dashboard in service-name order, then the project's other dashboards; the saved searches in the same service order.
func ReadSpec ¶ added in v0.1.46
ReadSpec assembles the Spec forge generate last wrote under projectDir. ok is false when there is none (a project that has not generated dashboards). A part of another version is an error that names the fix.
func WithoutProcessDashboards ¶ added in v1.0.9
WithoutProcessDashboards is sp for an environment that deploys no process: a static site has nothing for the overview, workloads and releases dashboards to measure (the overview would filter on the no-deployed-process sentinel), so only the dashboards that do not need a process remain.
type Thresholds ¶ added in v0.1.46
type Thresholds = dashspec.Thresholds
Thresholds is dashspec.Thresholds.