Documentation
¶
Overview ¶
Package topology owns the mode-selected service-topology read contract.
Index ¶
- Constants
- func IsHostEntity(service string) bool
- func NodeKind(service string) string
- type AggregateProvider
- func (p *AggregateProvider) Identity(context.Context) Identity
- func (p *AggregateProvider) PruneTopology()
- func (p *AggregateProvider) Snapshot(ctx context.Context, q Query) (Snapshot, error)
- func (*AggregateProvider) Source() Source
- func (p *AggregateProvider) TopologyEpoch() uint64
- func (p *AggregateProvider) TopologyRevision(tenant string) uint64
- func (p *AggregateProvider) TopologySnapshot(tenant string) aggregate.TopologySnapshot
- func (p *AggregateProvider) TopologyTenants() []string
- type Edge
- type Host
- type HostProjection
- type HostReader
- type Identity
- type InstanceCatalog
- type InstanceEdge
- type InstanceGraph
- func (g *InstanceGraph) Catalog(tenant string, start, end time.Time) InstanceCatalog
- func (g *InstanceGraph) Flush(ctx context.Context) error
- func (g *InstanceGraph) Observe(entity, traceID, spanID, parentID string, at time.Time, micros int64, ...)
- func (g *InstanceGraph) Prune(ctx context.Context) error
- func (g *InstanceGraph) Register(i InstanceIdentity, signal Signal, at time.Time) string
- func (g *InstanceGraph) Run(ctx context.Context)
- func (g *InstanceGraph) SetMetrics(m *telemetry.Metrics)
- func (g *InstanceGraph) Snapshot(ctx context.Context, tenant string, q InstanceQuery) (InstanceSnapshot, error)
- type InstanceIdentity
- type InstanceMetadata
- type InstanceNode
- type InstanceQuery
- type InstanceSnapshot
- type LegacyProvider
- type Metadata
- type Node
- type Provider
- type Query
- type Registry
- func (r *Registry) Evict(now time.Time) int
- func (r *Registry) Flush(ctx context.Context, db *gorm.DB) error
- func (r *Registry) Load(ctx context.Context, db *gorm.DB) (int, error)
- func (r *Registry) Overflow(tenant, kind string) uint64
- func (r *Registry) Register(tenant, service, host, workload, kind string, signal Signal, now time.Time) bool
- func (r *Registry) Run(ctx context.Context, db *gorm.DB, interval time.Duration)
- func (r *Registry) Snapshot() []ResourceEntry
- func (r *Registry) TenantSnapshot(tenant string) []ResourceEntry
- type ResourceEntry
- type ResourceKey
- type Signal
- type Snapshot
- type Source
Constants ¶
const ( // MaxHostsPerNode caps the hosts list stamped on one service-map node. MaxHostsPerNode = 20 // MaxServicesPerHost caps the services list carried by one host. MaxServicesPerHost = 100 )
Host projection bounds (#288). The registry already bounds hosts and service-host pairs per tenant; these bound what one response carries.
const ( KindService = "service" KindHost = "host" )
Node kinds. A host entity (IsHostEntity) is rendered as a host by every consumer: it is never a service, never carries a CALLS edge and never enters a service count.
const ( GraphWindow = 5 * time.Minute GraphFlushInterval = 5 * time.Second )
const ( DropInvalidIdentity = "invalid_identity" // empty tenant/service or over-length value DropOutOfWindow = "out_of_window" // older than retention or more than 2m in the future DropUnknownEntity = "unknown_entity" // span for a resource that was never admitted DropInvalidSpan = "invalid_span" // ID length or duration out of range DropEntityCap = "entity_cap" // graphMaxEntities reached DropChildrenCap = "children_cap" // graphMaxChildren waiting on one parent DropPendingCap = "pending_cap" // graphMaxPending unflushed buckets UnmatchedExpired = "expired" // parent did not arrive within graphSpanTTL UnmatchedEvicted = "evicted" // span buffer full; child evicted before its parent arrived UnmatchedEndpoint = "unknown_endpoint" // an endpoint entity was pruned before the join )
Loss reasons, reported per reason in the graph metadata and on otelcontext_instance_graph_lost_total{kind,reason}.
const ( // RegistryMaxHostsPerTenant bounds distinct non-empty hosts per tenant. RegistryMaxHostsPerTenant = 1000 // RegistryMaxEntriesPerTenant bounds service-host(-workload) entries per tenant. RegistryMaxEntriesPerTenant = 10000 // RegistryIdleTTL evicts an entry no signal has touched for this long. RegistryIdleTTL = 24 * time.Hour // RegistryMaxValueBytes bounds service, host and workload values; the // persisted columns are 255 bytes wide on every adapter and an over-length // value would poison every later flush of the same batch. RegistryMaxValueBytes = 255 // RegistryFlushInterval is the dirty-tick period used by Run. RegistryFlushInterval = 30 * time.Second )
Resource registry bounds (#279). Constants, mirroring the SignalStore caps: a shared __other__ host would be exactly the cross-host merge the registry exists to avoid, so overflow is counted and dropped, never collapsed.
const ( RegistryKindHost = "host" RegistryKindPair = "pair" RegistryKindLength = "length" )
Overflow kinds, also the metric label values.
const HostPrefix = "host/"
HostPrefix is the reserved service-name namespace of host entities (#280): a resource carrying host.id or host.name and no service.name is identified as HostPrefix + host.name (host.id when there is no name). The registry schema is unchanged; the entity kind is derived from the name.
Variables ¶
This section is empty.
Functions ¶
func IsHostEntity ¶
IsHostEntity reports whether service names a host entity.
Types ¶
type AggregateProvider ¶
type AggregateProvider struct {
HostReader
// contains filtered or unexported fields
}
AggregateProvider is both the ordinary mode-selected provider and the narrow aggregate projection source GraphRAG already consumes.
func NewAggregateProvider ¶
func NewAggregateProvider(engine *aggregate.Engine) (*AggregateProvider, error)
func (*AggregateProvider) PruneTopology ¶
func (p *AggregateProvider) PruneTopology()
func (*AggregateProvider) Source ¶
func (*AggregateProvider) Source() Source
func (*AggregateProvider) TopologyEpoch ¶
func (p *AggregateProvider) TopologyEpoch() uint64
The following methods implement graphrag.AggregateSource. Keeping that projection narrow avoids teaching GraphRAG about range queries.
func (*AggregateProvider) TopologyRevision ¶
func (p *AggregateProvider) TopologyRevision(tenant string) uint64
func (*AggregateProvider) TopologySnapshot ¶
func (p *AggregateProvider) TopologySnapshot(tenant string) aggregate.TopologySnapshot
func (*AggregateProvider) TopologyTenants ¶
func (p *AggregateProvider) TopologyTenants() []string
type Edge ¶
type Edge struct {
Source string `json:"source"`
Target string `json:"target"`
CallCount int64 `json:"call_count"`
AvgLatencyMs float64 `json:"avg_latency_ms"`
ErrorRate float64 `json:"error_rate"`
Status string `json:"status,omitempty"`
}
Edge is one directed service dependency.
type Host ¶
type Host struct {
Name string `json:"name"`
ServiceCount int `json:"service_count"`
Services []string `json:"services"`
LastSeen time.Time `json:"last_seen"`
Signals []string `json:"signals"`
}
Host is one host with the services observed on it. Services is sorted, never nil, capped at MaxServicesPerHost and never lists a host entity; ServiceCount is the uncapped total.
type HostProjection ¶
type HostProjection struct {
// Hosts is sorted by name and never nil.
Hosts []Host
// contains filtered or unexported fields
}
HostProjection is one tenant's host view derived from one registry snapshot: hosts with their services, and per service its hosts.
func ProjectHosts ¶
func ProjectHosts(entries []ResourceEntry) HostProjection
ProjectHosts folds registry entries of one tenant into a HostProjection. Entries without a host contribute nothing.
func (HostProjection) Host ¶
func (p HostProjection) Host(name string) (Host, bool)
Host returns the named host.
func (HostProjection) ServiceHosts ¶
func (p HostProjection) ServiceHosts(service string) (int, []string)
ServiceHosts returns how many hosts service was observed on and the first MaxHostsPerNode of them, sorted.
type HostReader ¶
type HostReader struct {
// contains filtered or unexported fields
}
HostReader is the single reader of the resource registry for every topology consumer. Both providers embed it, so legacy, shadow and aggregate answer host questions identically. Without a registry it projects nothing.
func (*HostReader) Hosts ¶
func (h *HostReader) Hosts(ctx context.Context) HostProjection
Hosts projects the registry for the tenant on ctx. It is built per call: the registry snapshot is already sorted and bounded per tenant.
func (*HostReader) SetRegistry ¶
func (h *HostReader) SetRegistry(r *Registry)
SetRegistry wires the registry read by Hosts.
type Identity ¶
type Identity struct {
Epoch string `json:"epoch,omitempty"`
Revision uint64 `json:"revision,omitempty"`
}
Identity orders full-replacement snapshots within one process generation.
type InstanceCatalog ¶ added in v0.6.4
type InstanceEdge ¶ added in v0.6.4
type InstanceEdge struct {
ID string `json:"id"`
Source string `json:"source"`
Target string `json:"target"`
Calls int64 `json:"calls"`
Errors int64 `json:"errors"`
Rate float64 `json:"request_rate_rps"`
AvgLatencyMS float64 `json:"avg_latency_ms"`
ErrorRate float64 `json:"error_rate"`
// contains filtered or unexported fields
}
type InstanceGraph ¶ added in v0.6.4
type InstanceGraph struct {
// contains filtered or unexported fields
}
InstanceGraph is a best-effort, pre-sampling visualization projection. A five-second dirty tick persists summaries; raw ingestion ACKs are not changed. A crash can lose the unflushed interval. Correlation is bounded and in-memory, with no raw trace/span IDs persisted by this projection.
func NewInstanceGraph ¶ added in v0.6.4
func (*InstanceGraph) Catalog ¶ added in v0.6.4
func (g *InstanceGraph) Catalog(tenant string, start, end time.Time) InstanceCatalog
Catalog reads bounded identity metadata, not raw telemetry or aggregate history. It is safe to call independently of the expensive graph read.
func (*InstanceGraph) Flush ¶ added in v0.6.4
func (g *InstanceGraph) Flush(ctx context.Context) error
Flush snapshots dirty values without holding the ingestion mutex during I/O. A failed transaction keeps the original pending values. Successful commit subtracts only that snapshot; concurrent observations remain pending.
func (*InstanceGraph) Observe ¶ added in v0.6.4
func (g *InstanceGraph) Observe(entity, traceID, spanID, parentID string, at time.Time, micros int64, request, failed bool)
Observe records one successfully accepted span before exemplar filtering. Both arrival orders work, including calls between copies of the same service. A parent in a different trace or tenant can never create an edge.
func (*InstanceGraph) Prune ¶ added in v0.6.4
func (g *InstanceGraph) Prune(ctx context.Context) error
Prune removes at most 1000 rows per tick. Query visibility always clamps to retention even when physical cleanup is behind.
func (*InstanceGraph) Register ¶ added in v0.6.4
func (g *InstanceGraph) Register(i InstanceIdentity, signal Signal, at time.Time) string
Register is called once per resource batch for all three signals. It records presence without inventing trace counts for metrics-only/logs-only resources.
func (*InstanceGraph) Run ¶ added in v0.6.4
func (g *InstanceGraph) Run(ctx context.Context)
func (*InstanceGraph) SetMetrics ¶ added in v0.6.8
func (g *InstanceGraph) SetMetrics(m *telemetry.Metrics)
SetMetrics wires loss counters and size gauges. Call before ingestion starts.
func (*InstanceGraph) Snapshot ¶ added in v0.6.4
func (g *InstanceGraph) Snapshot(ctx context.Context, tenant string, q InstanceQuery) (InstanceSnapshot, error)
Snapshot materializes at most 50,000 stored rows plus the bounded pending map. Scope is applied before storage reads, with at most 400 bind variables per query. The gate excludes a concurrent flush, preventing double counts between durable rows and pending values without blocking ingestion on I/O.
type InstanceIdentity ¶ added in v0.6.4
type InstanceIdentity struct {
Tenant, Environment, Namespace, Service, Instance, Host, Workload string
}
InstanceIdentity never derives environment from a host name. Explicit instance IDs are scoped by tenant, environment, namespace and service. Host/workload is a fallback; host alone is explicitly ambiguous.
type InstanceMetadata ¶ added in v0.6.4
type InstanceMetadata struct {
Start time.Time `json:"start"`
End time.Time `json:"end"`
ResolutionS int `json:"resolution_seconds"`
Coverage string `json:"coverage"`
Note string `json:"note"`
Truncated bool `json:"truncated"`
AvailableNodes int `json:"available_nodes"`
ReadRows int `json:"read_rows"`
PendingSpans int `json:"pending_parent_spans"`
Dropped uint64 `json:"process_dropped"`
Unmatched uint64 `json:"process_unmatched"`
DropReasons map[string]uint64 `json:"process_drop_reasons"`
MissReasons map[string]uint64 `json:"process_unmatched_reasons"`
LastLoss *time.Time `json:"last_loss,omitempty"`
LastFlush time.Time `json:"last_flush"`
FlushFailed bool `json:"flush_failed"`
}
type InstanceNode ¶ added in v0.6.4
type InstanceNode struct {
ID string `json:"id"`
ServiceID string `json:"service_id"`
Name string `json:"name"`
Namespace string `json:"namespace"`
Environment string `json:"environment"`
Instance string `json:"instance,omitempty"`
Identity string `json:"identity"`
Hosts []string `json:"hosts"`
Instances []string `json:"instances"`
InstanceCount int `json:"instance_count"`
UnresolvedCount int `json:"unresolved_count"`
Spans int64 `json:"spans"`
Requests int64 `json:"requests"`
Errors int64 `json:"errors"`
Rate float64 `json:"request_rate_rps"`
AvgLatencyMS float64 `json:"avg_latency_ms"`
ErrorRate float64 `json:"error_rate"`
// contains filtered or unexported fields
}
type InstanceQuery ¶ added in v0.6.4
type InstanceSnapshot ¶ added in v0.6.4
type InstanceSnapshot struct {
Nodes []InstanceNode `json:"nodes"`
Edges []InstanceEdge `json:"edges"`
Meta InstanceMetadata `json:"meta"`
}
type LegacyProvider ¶
type LegacyProvider struct {
HostReader
// contains filtered or unexported fields
}
LegacyProvider preserves the existing historical repository query and the current GraphRAG/graph/DB preference for live topology.
func NewLegacyProvider ¶
func (*LegacyProvider) Source ¶
func (*LegacyProvider) Source() Source
type Metadata ¶
type Metadata struct {
Source Source `json:"source,omitempty"`
Start time.Time `json:"start,omitempty"`
End time.Time `json:"end,omitempty"`
Coverage string `json:"coverage,omitempty"`
CoverageNote string `json:"coverage_note,omitempty"`
Epoch string `json:"epoch,omitempty"`
Revision uint64 `json:"revision,omitempty"`
Truncated bool `json:"truncated,omitempty"`
DroppedServices uint64 `json:"dropped_services,omitempty"`
DroppedOperations uint64 `json:"dropped_operations,omitempty"`
DroppedEdges uint64 `json:"dropped_edges,omitempty"`
DroppedMetrics uint64 `json:"dropped_metrics,omitempty"`
IdentityCoverage aggregate.IdentityCoverage `json:"identity_coverage"`
}
Metadata is additive ownership and completeness information.
type Node ¶
type Node struct {
Name string `json:"name"`
TotalTraces int64 `json:"total_traces"`
ErrorCount int64 `json:"error_count"`
AvgLatencyMs float64 `json:"avg_latency_ms"`
RequestRateRPS float64 `json:"request_rate_rps,omitempty"`
ErrorRate float64 `json:"error_rate,omitempty"`
P99LatencyMs float64 `json:"p99_latency_ms,omitempty"`
LatencyProvenance *latency.Provenance `json:"latency_provenance,omitempty"`
SpanCount int64 `json:"span_count,omitempty"`
HealthScore float64 `json:"health_score,omitempty"`
Status string `json:"status,omitempty"`
Alerts []string `json:"alerts,omitempty"`
// Host projection (#288), stamped by the provider from the resource
// registry. Kind is KindService or KindHost; Hosts is sorted and capped
// at MaxHostsPerNode while HostCount is the uncapped total.
Kind string `json:"kind,omitempty"`
HostCount int `json:"host_count,omitempty"`
Hosts []string `json:"hosts,omitempty"`
}
Node is the wire-neutral service projection shared by all consumers.
type Provider ¶
type Provider interface {
Source() Source
Identity(context.Context) Identity
Snapshot(context.Context, Query) (Snapshot, error)
// Hosts is the tenant-scoped host projection of the resource registry.
// Every provider answers it from the same registry, so legacy, shadow
// and aggregate agree on hosts.
Hosts(context.Context) HostProjection
}
Provider is selected once from AGGREGATE_MODE and injected into every live topology consumer.
type Query ¶
Query selects a range and an optional closed set of services. A zero range asks for the provider's current live replacement.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry is the bounded in-memory resource registry. Registration is one mutex acquisition and one map lookup; the already-present path allocates nothing.
func NewRegistry ¶
NewRegistry returns an empty registry. metrics may be nil.
func (*Registry) Evict ¶
Evict drops entries idle past RegistryIdleTTL at now and returns how many. Their rows are deleted by the next Flush.
func (*Registry) Flush ¶
Flush upserts dirty entries and deletes evicted rows. A failed write leaves the affected entries dirty (or evicted) for the next tick.
func (*Registry) Load ¶
Load reloads persisted entries through the same bounds as Register. Rows already idle past the TTL are loaded too; the first tick evicts them and the following flush deletes their rows.
func (*Registry) Overflow ¶
Overflow returns how many registrations the bound of kind refused for tenant.
func (*Registry) Register ¶
func (r *Registry) Register(tenant, service, host, workload, kind string, signal Signal, now time.Time) bool
Register records that signal arrived from the resource at now. It reports false when a per-tenant bound refused a new entry.
func (*Registry) Run ¶
Run evicts, publishes gauges and flushes on every tick until ctx is done. The caller flushes once more at shutdown.
func (*Registry) Snapshot ¶
func (r *Registry) Snapshot() []ResourceEntry
Snapshot returns every live entry ordered by key.
func (*Registry) TenantSnapshot ¶
func (r *Registry) TenantSnapshot(tenant string) []ResourceEntry
TenantSnapshot returns tenant's live entries ordered by key.
type ResourceEntry ¶
type ResourceEntry struct {
ResourceKey
// Kind names the slot that filled Workload (pod|container|process), or "".
Kind string
Signals Signal
LastSeen time.Time
}
ResourceEntry is one row of a read-only registry snapshot.
type ResourceKey ¶
ResourceKey identifies one registered resource. Host is host.id else host.name; Workload is k8s.pod.uid else container.id else process.pid. Both may be empty: a resource without a host registers the service alone.