Documentation
¶
Index ¶
- Variables
- func NewExtension(opts ...ConfigOption) forge.Extension
- func TracingMiddleware(store *collector.TraceStore, basePath string, captureRequestBody ...bool) forge.Middleware
- type Config
- type ConfigOption
- func WithBasePath(path string) ConfigOption
- func WithCSRF(enabled bool) ConfigOption
- func WithConfig(config Config) ConfigOption
- func WithContractMaxBodyBytes(n int64) ConfigOption
- func WithContractSecurity(enabled bool) ConfigOption
- func WithDiscovery(enabled bool) ConfigOption
- func WithDiscoveryPollInterval(interval time.Duration) ConfigOption
- func WithDiscoveryTag(tag string) ConfigOption
- func WithEnableAuth(enabled bool) ConfigOption
- func WithExport(enabled bool) ConfigOption
- func WithExportFormats(formats []string) ConfigOption
- func WithHistoryDuration(duration time.Duration) ConfigOption
- func WithLoginPath(path string) ConfigOption
- func WithMaxDataPoints(maxPoints int) ConfigOption
- func WithMemoryProfile(profile MemoryProfile) ConfigOption
- func WithRefreshInterval(interval time.Duration) ConfigOption
- func WithRequireConfig(required bool) ConfigOption
- func WithRequiredRoles(roles []string) ConfigOption
- func WithTraceCaptureRequestBody(enabled bool) ConfigOption
- func WithTraceIdleTTL(duration time.Duration) ConfigOption
- func WithTraceMaxCount(count int) ConfigOption
- func WithTraceMaxSpansPerTrace(n int) ConfigOption
- func WithTraceRetention(duration time.Duration) ConfigOption
- type ContractContributorAware
- type DashboardAuthAware
- type DashboardStatus
- type DashboardStatusAware
- type Extension
- func (e *Extension) AuthChecker() dashauth.AuthChecker
- func (e *Extension) BasePath() string
- func (e *Extension) CSRFManager() *security.CSRFManager
- func (e *Extension) Collector() *collector.DataCollector
- func (e *Extension) Dependencies() []string
- func (e *Extension) EnableAuth()
- func (e *Extension) Health(ctx context.Context) error
- func (e *Extension) History() *collector.DataHistory
- func (e *Extension) Register(app forge.App) error
- func (e *Extension) RegisterRemoteContractContributor(ctx context.Context, baseURL, apiKey string) error
- func (e *Extension) SetAuthChecker(checker dashauth.AuthChecker)
- func (e *Extension) SetDiscoveryService(svc dashboarddiscovery.DiscoveryService)
- func (e *Extension) SetRequiredRoles(roles []string)
- func (e *Extension) SetTenantResolver(resolver dashauth.TenantResolver)
- func (e *Extension) Start(ctx context.Context) error
- func (e *Extension) Stop(ctx context.Context) error
- func (e *Extension) TenantResolver() dashauth.TenantResolver
- func (e *Extension) TraceStore() *collector.TraceStore
- func (e *Extension) UnregisterRemoteContractContributor(name string)
- type MemoryProfile
Constants ¶
This section is empty.
Variables ¶
var ( // ErrCollectorNotInitialized is returned when the data collector is not initialized. ErrCollectorNotInitialized = errors.New("dashboard: collector not initialized") )
Functions ¶
func NewExtension ¶
func NewExtension(opts ...ConfigOption) forge.Extension
NewExtension creates a new dashboard extension.
func TracingMiddleware ¶ added in v1.2.0
func TracingMiddleware(store *collector.TraceStore, basePath string, captureRequestBody ...bool) forge.Middleware
TracingMiddleware creates a forge middleware that auto-captures request traces and feeds them into the given TraceStore. Only dashboard internals (static assets, SSE streams, and bridge calls) are excluded — page navigations and API calls are traced so the tracing UI has data out of the box.
Types ¶
type Config ¶
type Config struct {
// BasePath prefixes every route the extension mounts.
BasePath string `json:"base_path" yaml:"base_path"`
// Data collection
RefreshInterval time.Duration `json:"refresh_interval" yaml:"refresh_interval"`
HistoryDuration time.Duration `json:"history_duration" yaml:"history_duration"`
MaxDataPoints int `json:"max_data_points" yaml:"max_data_points"`
// Tracing
TraceMaxCount int `json:"trace_max_count" yaml:"trace_max_count"`
TraceRetention time.Duration `json:"trace_retention" yaml:"trace_retention"`
// TraceMaxSpansPerTrace caps how many spans one trace retains. A single
// long-lived trace, such as a websocket, would otherwise grow unbounded.
TraceMaxSpansPerTrace int `json:"trace_max_spans_per_trace" yaml:"trace_max_spans_per_trace"`
// TraceIdleTTL is how long after the last dashboard request spans keep being
// retained. A negative duration disables the gate, retaining always (the
// pre-gate behaviour). Zero is not a reliable way to disable it: under a
// ConfigManager, config merging (see extension_config.go) only overrides a
// field when the source value is non-zero, so an explicit 0 here is
// silently skipped and the default survives.
TraceIdleTTL time.Duration `json:"trace_idle_ttl" yaml:"trace_idle_ttl"`
// TraceCaptureRequestBody retains a bounded, redacted JSON request body in
// the in-memory trace store. It is opt-in because arbitrary fields may hold
// private data even after credential-shaped keys are removed.
TraceCaptureRequestBody bool `json:"trace_capture_request_body" yaml:"trace_capture_request_body"`
// Security
EnableCSRF bool `json:"enable_csrf" yaml:"enable_csrf"`
// EnableContractSecurity gates CSRF validation, idempotency dedup, and
// distributed tracing on the contract envelope endpoint. Default true;
// set to false during a rollout window where clients have not yet
// adopted CSRF tokens or the idempotency-key contract.
EnableContractSecurity bool `json:"enable_contract_security" yaml:"enable_contract_security"`
// ContractMaxBodyBytes caps the contract envelope a client may POST.
// Zero or less means transport.DefaultMaxBodyBytes (1 MiB).
ContractMaxBodyBytes int64 `json:"contract_max_body_bytes" yaml:"contract_max_body_bytes"`
// Authentication
EnableAuth bool `json:"enable_auth" yaml:"enable_auth"`
// LoginPath is where a signed-out user is sent, relative to BasePath. The
// dashboard serves no login page itself: the principal endpoint reports
// this path in its 401 so the client knows where to redirect.
LoginPath string `json:"login_path" yaml:"login_path"`
// RequiredRoles, when non-empty, restricts dashboard access to users
// carrying at least one matching role. The principal endpoint returns
// 403 PERMISSION_DENIED for users who don't qualify. Rendering that as
// an "access denied" screen is the client's job.
RequiredRoles []string `json:"required_roles" yaml:"required_roles"`
// Discovery. With EnableDiscovery on and a discovery service set through
// SetDiscoveryService, services registered under DiscoveryTag that serve
// a contract manifest are added as remote contributors automatically.
EnableDiscovery bool `json:"enable_discovery" yaml:"enable_discovery"`
DiscoveryTag string `json:"discovery_tag" yaml:"discovery_tag"`
DiscoveryPollInterval time.Duration `json:"discovery_poll_interval" yaml:"discovery_poll_interval"`
// Export
EnableExport bool `json:"enable_export" yaml:"enable_export"`
ExportFormats []string `json:"export_formats" yaml:"export_formats"`
// Internal
RequireConfig bool `json:"-" yaml:"-"`
}
Config contains dashboard extension configuration.
func DefaultConfig ¶
func DefaultConfig() Config
DefaultConfig returns the default dashboard configuration.
type ConfigOption ¶
type ConfigOption func(*Config)
ConfigOption is a functional option for Config.
func WithBasePath ¶
func WithBasePath(path string) ConfigOption
WithBasePath sets the base URL path for the dashboard.
func WithCSRF ¶ added in v0.9.12
func WithCSRF(enabled bool) ConfigOption
WithCSRF enables or disables CSRF token protection.
func WithContractMaxBodyBytes ¶ added in v1.12.0
func WithContractMaxBodyBytes(n int64) ConfigOption
WithContractMaxBodyBytes caps the contract envelope a client may POST. Larger bodies are refused with 413 before they are decoded. Zero or less keeps the 1 MiB default.
func WithContractSecurity ¶ added in v1.6.4
func WithContractSecurity(enabled bool) ConfigOption
WithContractSecurity enables or disables the contract envelope's security stack (CSRF validation, idempotency dedup, request tracing). Defaults to true; switching off should be reserved for rollout windows where clients have not yet adopted CSRF tokens or idempotency keys.
func WithDiscovery ¶ added in v0.9.12
func WithDiscovery(enabled bool) ConfigOption
WithDiscovery turns on automatic registration of remote contributors found through the discovery service set with SetDiscoveryService.
func WithDiscoveryPollInterval ¶ added in v0.9.12
func WithDiscoveryPollInterval(interval time.Duration) ConfigOption
WithDiscoveryPollInterval sets how often discovery is checked for new, changed or departed contributors.
func WithDiscoveryTag ¶ added in v0.9.12
func WithDiscoveryTag(tag string) ConfigOption
WithDiscoveryTag sets the discovery tag a service registers under to be picked up as a dashboard contributor.
func WithEnableAuth ¶ added in v0.10.0
func WithEnableAuth(enabled bool) ConfigOption
WithEnableAuth enables or disables authentication support.
func WithExport ¶
func WithExport(enabled bool) ConfigOption
WithExport enables or disables export functionality.
func WithExportFormats ¶ added in v0.9.12
func WithExportFormats(formats []string) ConfigOption
WithExportFormats sets the supported export formats.
func WithHistoryDuration ¶
func WithHistoryDuration(duration time.Duration) ConfigOption
WithHistoryDuration sets the data retention duration.
func WithLoginPath ¶ added in v0.10.0
func WithLoginPath(path string) ConfigOption
WithLoginPath sets the path, relative to BasePath, that the principal endpoint reports for signed-out users (e.g. "/auth/login").
func WithMaxDataPoints ¶
func WithMaxDataPoints(maxPoints int) ConfigOption
WithMaxDataPoints sets the maximum number of data points to retain.
func WithMemoryProfile ¶ added in v1.6.0
func WithMemoryProfile(profile MemoryProfile) ConfigOption
WithMemoryProfile auto-tunes data collection and retention settings based on the available system memory. Individual settings applied after this option will override the profile defaults.
func WithRefreshInterval ¶
func WithRefreshInterval(interval time.Duration) ConfigOption
WithRefreshInterval sets the data collection refresh interval.
func WithRequireConfig ¶
func WithRequireConfig(required bool) ConfigOption
WithRequireConfig requires config from ConfigManager.
func WithRequiredRoles ¶ added in v1.6.4
func WithRequiredRoles(roles []string) ConfigOption
WithRequiredRoles restricts dashboard access to users carrying at least one of the given roles. Pass nil/empty to allow all authenticated users. Auth extensions (e.g. authsome) call this via Extension.SetRequiredRoles when their config declares a role gate; deployments can also configure it directly via this option.
func WithTraceCaptureRequestBody ¶ added in v1.11.2
func WithTraceCaptureRequestBody(enabled bool) ConfigOption
WithTraceCaptureRequestBody enables bounded JSON request-body inspection.
func WithTraceIdleTTL ¶ added in v1.11.0
func WithTraceIdleTTL(duration time.Duration) ConfigOption
WithTraceIdleTTL sets how long after the last dashboard request traces keep being collected. Pass a negative duration to collect always, disabling the gate. Passing zero is not reliable for this: under a ConfigManager, config merging only overrides a field when the source value is non-zero, so an explicit zero here can be silently skipped in favor of the existing value.
func WithTraceMaxCount ¶ added in v1.6.0
func WithTraceMaxCount(count int) ConfigOption
WithTraceMaxCount sets the maximum number of traces kept in memory.
func WithTraceMaxSpansPerTrace ¶ added in v1.11.0
func WithTraceMaxSpansPerTrace(n int) ConfigOption
WithTraceMaxSpansPerTrace sets how many spans a single trace retains.
func WithTraceRetention ¶ added in v1.6.0
func WithTraceRetention(duration time.Duration) ConfigOption
WithTraceRetention sets the retention duration for traces.
type ContractContributorAware ¶ added in v1.6.4
type ContractContributorAware interface {
RegisterContractContributor(
disp *dispatcher.Dispatcher,
reg contract.Registry,
wreg contract.WardenRegistry,
) error
}
ContractContributorAware is an optional interface that Forge extensions can implement to register a contract-based dashboard contributor (the slice (f)+ shape — declarative YAML manifest + typed dispatcher handlers). The dashboard auto-discovers extensions implementing this interface during Start() and calls RegisterContractContributor with the dashboard's contract registry, warden registry, and dispatcher.
This is the only way an extension contributes to the dashboard. Its UI ships separately, as a React plugin that talks to these intents.
Example implementation:
func (e *StreamingExtension) RegisterContractContributor(
disp *dispatcher.Dispatcher,
reg contract.Registry,
wreg contract.WardenRegistry,
) error {
return streamingcontract.Register(disp, reg, wreg, streamingcontract.Deps{
Manager: func() streaming.Manager { return e.manager },
Config: func() streaming.Config { return e.config },
})
}
type DashboardAuthAware ¶ added in v1.2.0
type DashboardAuthAware interface {
RegisterDashboardAuth(ext *Extension)
}
DashboardAuthAware is an optional interface that Forge extensions can implement to provide authentication for the dashboard. The dashboard auto-discovers extensions implementing this interface during Start() and calls RegisterDashboardAuth with itself, allowing the extension to set up auth checking, required roles, and tenant resolution.
Example implementation:
func (a *AuthExtension) RegisterDashboardAuth(ext *dashboard.Extension) {
ext.SetAuthChecker(myAuthChecker)
ext.EnableAuth()
}
Wiring an auth extension into the contract:
Auth extensions plug in by implementing both DashboardAuthAware *and* ContractContributorAware:
- DashboardAuthAware.RegisterDashboardAuth wires the AuthChecker so /api/dashboard/v1/principal returns the current user. That endpoint distinguishes the 401 envelope (auth required) from the 200 `{authenticated:false}` envelope (auth disabled), so a client can tell "log in" apart from "auth is off".
- ContractContributorAware.RegisterContractContributor registers the `auth.login` command intent (and optionally `auth.logout`) on the dispatcher.
This is the whole server side. The dashboard serves no login page of its own: the React dashboard reads /principal to decide whether to show a login gate, and the login UI itself belongs to the auth extension's plugin.
Example combined integration sketch:
func (a *AuthsomeExtension) RegisterDashboardAuth(ext *dashboard.Extension) {
ext.SetAuthChecker(a.checker)
ext.EnableAuth()
}
func (a *AuthsomeExtension) RegisterContractContributor(
disp *dispatcher.Dispatcher,
reg contract.Registry,
wreg contract.WardenRegistry,
) error {
return authsomecontract.Register(disp, reg, wreg, authsomecontract.Deps{
Sessions: a.sessions, // registers the `auth.login` command
})
}
type DashboardStatus ¶ added in v1.11.1
type DashboardStatus struct {
// Version is the extension's semver, checked against the plugin's
// `requires` range. Empty means "do not check".
Version string `json:"version,omitempty"`
// Configured reports whether the extension has everything it needs to
// serve. False makes the dashboard render the plugin's setup guide.
Configured bool `json:"configured"`
// Message is optional detail shown in the setup panel.
Message string `json:"message,omitempty"`
}
DashboardStatus is what an extension reports about itself to the dashboard.
Set Configured explicitly on every value you return. The struct's zero value is Configured=false, the restrictive answer, so a bare DashboardStatus{} returned from a switch default asks the dashboard for a setup panel.
The permissive default lives elsewhere: an extension that does not implement DashboardStatusAware at all is reported with an empty Version and Configured=true, so the plugin host skips the version check rather than failing it, and renders the plugin normally. Nobody has to implement this to keep working.
type DashboardStatusAware ¶ added in v1.11.1
type DashboardStatusAware interface {
DashboardStatus() DashboardStatus
}
DashboardStatusAware is an optional interface a Forge extension can implement to tell the dashboard its version and whether it is configured.
Without it the dashboard would have to infer setup state by calling a data method and interpreting the failure, which cannot distinguish "not configured yet" from "configured but failing" from "you lack permission". Those are three different screens.
type Extension ¶
type Extension struct {
*forge.BaseExtension
// contains filtered or unexported fields
}
Extension serves the dashboard's data plane: the contract API under {BasePath}/api/dashboard/v1 that every dashboard client talks to, plus the collector, trace store and export endpoints behind it. It serves no web pages. The dashboard UI is a separate React app built from the @forge-go/dashboard-* packages, and extensions contribute to it by registering contract intents (ContractContributorAware) and shipping a plugin.
func (*Extension) AuthChecker ¶ added in v0.10.0
func (e *Extension) AuthChecker() dashauth.AuthChecker
AuthChecker returns the configured authentication checker. Returns nil if none is set.
func (*Extension) BasePath ¶ added in v1.12.0
BasePath returns the prefix every dashboard route is mounted under.
func (*Extension) CSRFManager ¶ added in v0.9.12
func (e *Extension) CSRFManager() *security.CSRFManager
CSRFManager returns the CSRF token manager. Returns nil if CSRF is disabled.
func (*Extension) Collector ¶ added in v0.8.0
func (e *Extension) Collector() *collector.DataCollector
Collector returns the data collector instance.
func (*Extension) Dependencies ¶
Dependencies returns extension dependencies.
func (*Extension) EnableAuth ¶ added in v1.2.0
func (e *Extension) EnableAuth()
EnableAuth turns on authentication support. Auth extensions such as authsome call this from RegisterDashboardAuth. With auth on, the principal endpoint answers 401 for a signed-out caller instead of an anonymous 200.
func (*Extension) History ¶ added in v0.8.0
func (e *Extension) History() *collector.DataHistory
History returns the data history instance.
func (*Extension) RegisterRemoteContractContributor ¶ added in v1.6.4
func (e *Extension) RegisterRemoteContractContributor(ctx context.Context, baseURL, apiKey string) error
RegisterRemoteContractContributor registers a contract contributor whose handlers live in another service. The dashboard fetches the upstream's manifest, validates it, records the endpoint, and installs a forwarding dispatcher (idempotently) so subsequent requests for any of the remote's intents are proxied to the upstream over HTTP.
Slice (m) added this so a single dashboard can aggregate contributors from multiple microservices.
baseURL is the upstream service root (e.g. https://svc.internal:8443); the manifest endpoint is fetched at <baseURL>/_forge/contract/manifest and envelopes are POSTed to <baseURL>/_forge/contract/dispatch. apiKey, when non-empty, is sent as Authorization: Bearer on dashboard→service hops; end-user identity flows in parallel via X-Forwarded-Authorization and X-Forwarded-Cookie.
func (*Extension) SetAuthChecker ¶ added in v0.10.0
func (e *Extension) SetAuthChecker(checker dashauth.AuthChecker)
SetAuthChecker configures the authentication checker used to validate requests. Call this after Register() and before Start(). When auth is enabled, the checker is invoked on every request to populate the user context.
Example using the adapter for the forge auth extension:
checker := dashauth.NewAuthExtensionChecker(authRegistry, "oidc") dashExt.SetAuthChecker(checker)
func (*Extension) SetDiscoveryService ¶ added in v0.9.12
func (e *Extension) SetDiscoveryService(svc dashboarddiscovery.DiscoveryService)
SetDiscoveryService sets the discovery service used to find remote contributors. Call it before the app runs, typically from a PhaseAfterRegister hook, and turn discovery on with WithDiscovery(true).
A remote service takes part by serving its intents with contract/server and registering itself in discovery under DiscoveryTag. An instance's "forge-api-key" metadata, when set, is sent to it as a bearer token.
func (*Extension) SetRequiredRoles ¶ added in v1.6.4
SetRequiredRoles restricts dashboard access to authenticated users that hold at least one of the given roles. Pass nil/empty to clear the gate. Auth extensions like authsome call this from RegisterDashboardAuth when their own configuration declares a role list. The principal endpoint returns 403 PERMISSION_DENIED for users who don't qualify. Rendering that as an "access denied" screen is the client's job.
func (*Extension) SetTenantResolver ¶ added in v1.2.0
func (e *Extension) SetTenantResolver(resolver dashauth.TenantResolver)
SetTenantResolver configures the tenant resolver used to populate tenant context on every request. Call this after Register() and before Start(). When configured, the contract handlers can read tenant info via dashauth.TenantFromContext(ctx).
A default ScopeTenantResolver is available that reads forge.Scope from the request context:
dashExt.SetTenantResolver(dashauth.ScopeTenantResolver{})
func (*Extension) TenantResolver ¶ added in v1.2.0
func (e *Extension) TenantResolver() dashauth.TenantResolver
TenantResolver returns the configured tenant resolver. Returns nil if none is set.
func (*Extension) TraceStore ¶ added in v1.2.0
func (e *Extension) TraceStore() *collector.TraceStore
TraceStore returns the trace store instance.
func (*Extension) UnregisterRemoteContractContributor ¶ added in v1.6.4
UnregisterRemoteContractContributor removes a previously registered remote. Safe to call for unknown names; future dispatches to the contributor will fall through to CodeNotFound.
type MemoryProfile ¶ added in v1.6.0
type MemoryProfile string
MemoryProfile controls memory usage tuning for the dashboard. Use "low" for 512MB systems, "medium" for 1-2GB, "high" for 4GB+.
const ( // MemoryProfileLow tunes for 512MB systems with minimal history and trace retention. MemoryProfileLow MemoryProfile = "low" // MemoryProfileMedium is the default, suitable for 1-2GB systems. MemoryProfileMedium MemoryProfile = "medium" // MemoryProfileHigh allows maximum history and trace retention for 4GB+ systems. MemoryProfileHigh MemoryProfile = "high" )
Directories
¶
| Path | Synopsis |
|---|---|
|
Package dashauth provides authentication and authorization abstractions for the dashboard extension.
|
Package dashauth provides authentication and authorization abstractions for the dashboard extension. |
|
Package contract defines the declarative, single-endpoint contract for the admin dashboard: contributor manifests, request/response envelopes, the permission model, and the per-contributor version negotiation protocol.
|
Package contract defines the declarative, single-endpoint contract for the admin dashboard: contributor manifests, request/response envelopes, the permission model, and the per-contributor version negotiation protocol. |
|
dispatcher
Package dispatcher implements transport.Dispatcher and transport.SubscriptionSource against a function-table of registered handlers.
|
Package dispatcher implements transport.Dispatcher and transport.SubscriptionSource against a function-table of registered handlers. |
|
idempotency
Package idempotency provides command deduplication for the dashboard contract: a Store interface plus an in-memory implementation.
|
Package idempotency provides command deduplication for the dashboard contract: a Store interface plus an in-memory implementation. |
|
loader
validate.go
|
validate.go |
|
pilot
Package pilot ships the migrated dashboard contributor used to validate the contract end-to-end: extensions.list, services.list, services.detail, and the metrics.summary subscription, all wired against the existing collector and contributor registry.
|
Package pilot ships the migrated dashboard contributor used to validate the contract end-to-end: extensions.list, services.list, services.detail, and the metrics.summary subscription, all wired against the existing collector and contributor registry. |
|
remote
Package remote implements the contract dispatcher's HTTP forwarding layer.
|
Package remote implements the contract dispatcher's HTTP forwarding layer. |
|
server
Package server exposes the two HTTP endpoints a non-dashboard service needs to advertise itself as a contract contributor that other dashboards can discover + dispatch into.
|
Package server exposes the two HTTP endpoints a non-dashboard service needs to advertise itself as a contract contributor that other dashboards can discover + dispatch into. |
|
transport
capabilities.go
|
capabilities.go |
|
Package discovery registers remote dashboard contributors found through a service discovery backend.
|
Package discovery registers remote dashboard contributors found through a service discovery backend. |
|
examples
|
|
|
basic
command
Package main demonstrates a basic dashboard setup with default configuration and no contributors registered.
|
Package main demonstrates a basic dashboard setup with default configuration and no contributors registered. |