mirror of
https://github.com/hanzoai/o11y.git
synced 2026-10-15 12:58:33 +00:00
An op learns its address from zip.OpOf and zip.AddressOf, so the claim table, the five declaring verbs and the address bookkeeping are gone. A host that declares one of these addresses itself now gets a Build conflict from zip. Co-authored-by: Hanzo Dev <[email protected]>
215 lines
9.2 KiB
Go
215 lines
9.2 KiB
Go
package o11y
|
|
|
|
// The SPAN-MAPPER face — the ingest-time rules that move or copy span
|
|
// attributes into resource attributes before a span is stored — as TYPED ops.
|
|
//
|
|
// These were eight of the routes that reached traffic only through the
|
|
// delegation wildcard, and a route behind a wildcard is in no document: no SDK
|
|
// method, no CLI command, no agent tool, no reference page. Span mappers are the
|
|
// one surface a customer must edit to fix their own telemetry shape, and until
|
|
// now they could only do it from a hand-written HTTP call. Typing them is what
|
|
// puts the eight operations in the document and therefore in every projection
|
|
// built from it.
|
|
//
|
|
// A GROUP AND ITS MAPPERS. A group carries the condition that decides WHICH
|
|
// spans it applies to; the mappers under it carry the moves. That nesting is the
|
|
// path shape (/span_mapper_groups/:groupId/span_mappers/:mapperId) and it is why
|
|
// the mapper ops take two ids.
|
|
//
|
|
// THE WIRE DOES NOT MOVE: each op hands the call to the SAME runtime handler the
|
|
// wildcard delegates to (relay.go), so the ViewAccess read gate and the
|
|
// AdminAccess write gate the runtime has always run still run, in the order they
|
|
// always did. The four writes answer 204 with no body, and the ops declare that
|
|
// status rather than inventing a payload.
|
|
|
|
//go:generate go run github.com/zap-proto/zip/cmd/zipdoc
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
|
|
"github.com/hanzoai/o11y/pkg/types/spantypes"
|
|
"github.com/zap-proto/zip"
|
|
)
|
|
|
|
// mountSpanMappers registers the eight typed span-mapper ops.
|
|
func mountSpanMappers(app *zip.App) {
|
|
// The group is o11yRoot, not o11yRoot+"/span_mapper_groups": a zip group
|
|
// with the collection as its prefix would register the collection routes at
|
|
// the empty sub-path, which lands them on a TRAILING SLASH the runtime does
|
|
// not serve. The collection is a path, not a prefix.
|
|
g := app.Group(o11yRoot)
|
|
|
|
g.Get("/span_mapper_groups", spanMapperGroups, op("ListSpanMapperGroups"))
|
|
g.Post("/span_mapper_groups", spanMapperGroupCreate, op("CreateSpanMapperGroup"), zip.WithStatus(http.StatusCreated))
|
|
g.Patch("/span_mapper_groups/:groupId", spanMapperGroupUpdate, op("UpdateSpanMapperGroup"), zip.WithStatus(http.StatusNoContent))
|
|
g.Delete("/span_mapper_groups/:groupId", spanMapperGroupDelete, op("DeleteSpanMapperGroup"), zip.WithStatus(http.StatusNoContent))
|
|
|
|
g.Get("/span_mapper_groups/:groupId/span_mappers", spanMappers, op("ListSpanMappers"))
|
|
g.Post("/span_mapper_groups/:groupId/span_mappers", spanMapperCreate, op("CreateSpanMapper"), zip.WithStatus(http.StatusCreated))
|
|
g.Patch("/span_mapper_groups/:groupId/span_mappers/:mapperId", spanMapperUpdate, op("UpdateSpanMapper"), zip.WithStatus(http.StatusNoContent))
|
|
g.Delete("/span_mapper_groups/:groupId/span_mappers/:mapperId", spanMapperDelete, op("DeleteSpanMapper"), zip.WithStatus(http.StatusNoContent))
|
|
}
|
|
|
|
// ── groups ────────────────────────────────────────────────────────────────────
|
|
|
|
// spanMapperGroups lists the caller's org's mapping groups, optionally only the
|
|
// enabled ones.
|
|
//
|
|
// Callers need the viewer role; the runtime's own gate enforces it.
|
|
func spanMapperGroups(ctx context.Context, in *O11ySpanMapperGroupsIn) (*O11ySpanMapperGroupsOut, error) {
|
|
out := new(O11ySpanMapperGroupsOut)
|
|
return out, relay(ctx, query("enabled", in.Enabled), nil, out)
|
|
}
|
|
|
|
// spanMapperGroupCreate creates a mapping group: the name it is known by, the
|
|
// span and resource attributes whose presence selects a span into it, and
|
|
// whether it is on.
|
|
//
|
|
// Callers need the admin role; the runtime's own gate enforces it.
|
|
func spanMapperGroupCreate(ctx context.Context, in *spantypes.PostableSpanMapperGroup) (*O11ySpanMapperGroupOut, error) {
|
|
out := new(O11ySpanMapperGroupOut)
|
|
return out, relay(ctx, nil, in, out)
|
|
}
|
|
|
|
// spanMapperGroupUpdate changes a group's name, condition or enabled state.
|
|
// Every field is optional and only the ones sent are applied.
|
|
//
|
|
// Callers need the admin role; the runtime's own gate enforces it.
|
|
func spanMapperGroupUpdate(ctx context.Context, in *O11ySpanMapperGroupUpdateIn) (*struct{}, error) {
|
|
return nil, relay(ctx, nil, in.UpdatableSpanMapperGroup, nil)
|
|
}
|
|
|
|
// spanMapperGroupDelete deletes a mapping group and every mapper under it.
|
|
//
|
|
// Callers need the admin role; the runtime's own gate enforces it.
|
|
func spanMapperGroupDelete(ctx context.Context, in *O11ySpanMapperGroupRef) (*struct{}, error) {
|
|
return nil, relay(ctx, nil, nil, nil)
|
|
}
|
|
|
|
// ── mappers ───────────────────────────────────────────────────────────────────
|
|
|
|
// spanMappers lists the mappers belonging to one group, in the order they are
|
|
// applied.
|
|
//
|
|
// Callers need the viewer role; the runtime's own gate enforces it.
|
|
func spanMappers(ctx context.Context, in *O11ySpanMapperGroupRef) (*O11ySpanMappersOut, error) {
|
|
out := new(O11ySpanMappersOut)
|
|
return out, relay(ctx, nil, nil, out)
|
|
}
|
|
|
|
// spanMapperCreate adds a mapper to a group: which field context it reads, the
|
|
// move or copy it performs, and whether it is on.
|
|
//
|
|
// Callers need the admin role; the runtime's own gate enforces it.
|
|
func spanMapperCreate(ctx context.Context, in *O11ySpanMapperCreateIn) (*O11ySpanMapperOut, error) {
|
|
out := new(O11ySpanMapperOut)
|
|
return out, relay(ctx, nil, in.PostableSpanMapper, out)
|
|
}
|
|
|
|
// spanMapperUpdate changes a mapper's field context, config or enabled state.
|
|
// Every field is optional and only the ones sent are applied.
|
|
//
|
|
// Callers need the admin role; the runtime's own gate enforces it.
|
|
func spanMapperUpdate(ctx context.Context, in *O11ySpanMapperUpdateIn) (*struct{}, error) {
|
|
return nil, relay(ctx, nil, in.UpdatableSpanMapper, nil)
|
|
}
|
|
|
|
// spanMapperDelete deletes one mapper from a group.
|
|
//
|
|
// Callers need the admin role; the runtime's own gate enforces it.
|
|
func spanMapperDelete(ctx context.Context, in *O11ySpanMapperRef) (*struct{}, error) {
|
|
return nil, relay(ctx, nil, nil, nil)
|
|
}
|
|
|
|
// groupPath and mapperPath are the one place these ids become a path. Each id
|
|
// goes on VERBATIM, as the segment the router matched.
|
|
func groupPath(groupID string) string { return o11yRoot + "/span_mapper_groups/" + groupID }
|
|
|
|
func mapperPath(groupID, mapperID string) string {
|
|
return groupPath(groupID) + "/span_mappers/" + mapperID
|
|
}
|
|
|
|
// ── inputs ────────────────────────────────────────────────────────────────────
|
|
|
|
// O11ySpanMapperGroupsIn narrows the group listing.
|
|
type O11ySpanMapperGroupsIn struct {
|
|
// Enabled lists only the groups that are on. False lists all of them —
|
|
// which is what the runtime has always read an absent parameter as.
|
|
Enabled bool `json:"-" url:"enabled"`
|
|
}
|
|
|
|
// O11ySpanMapperGroupRef names one mapping group.
|
|
type O11ySpanMapperGroupRef struct {
|
|
// GroupID is the group's id. Required.
|
|
GroupID string `json:"-" url:"groupId" validate:"required"`
|
|
}
|
|
|
|
// O11ySpanMapperGroupUpdateIn names the group and carries the change.
|
|
type O11ySpanMapperGroupUpdateIn struct {
|
|
// GroupID is the group to update. Required.
|
|
GroupID string `json:"-" url:"groupId" validate:"required"`
|
|
|
|
spantypes.UpdatableSpanMapperGroup
|
|
}
|
|
|
|
// O11ySpanMapperRef names one mapper inside its group.
|
|
type O11ySpanMapperRef struct {
|
|
// GroupID is the group the mapper belongs to. Required.
|
|
GroupID string `json:"-" url:"groupId" validate:"required"`
|
|
// MapperID is the mapper's id. Required.
|
|
MapperID string `json:"-" url:"mapperId" validate:"required"`
|
|
}
|
|
|
|
// O11ySpanMapperCreateIn names the group and describes the mapper to add.
|
|
type O11ySpanMapperCreateIn struct {
|
|
// GroupID is the group to add to. Required.
|
|
GroupID string `json:"-" url:"groupId" validate:"required"`
|
|
|
|
spantypes.PostableSpanMapper
|
|
}
|
|
|
|
// O11ySpanMapperUpdateIn names the mapper and carries the change.
|
|
type O11ySpanMapperUpdateIn struct {
|
|
// GroupID is the group the mapper belongs to. Required.
|
|
GroupID string `json:"-" url:"groupId" validate:"required"`
|
|
// MapperID is the mapper to update. Required.
|
|
MapperID string `json:"-" url:"mapperId" validate:"required"`
|
|
|
|
spantypes.UpdatableSpanMapper
|
|
}
|
|
|
|
// ── answers ───────────────────────────────────────────────────────────────────
|
|
|
|
// O11ySpanMapperGroupsOut is the org's mapping groups.
|
|
type O11ySpanMapperGroupsOut struct {
|
|
// Status is "success".
|
|
Status string `json:"status"`
|
|
// Data holds the groups.
|
|
Data spantypes.GettableSpanMapperGroups `json:"data"`
|
|
}
|
|
|
|
// O11ySpanMapperGroupOut is one mapping group.
|
|
type O11ySpanMapperGroupOut struct {
|
|
// Status is "success".
|
|
Status string `json:"status"`
|
|
// Data is the group.
|
|
Data spantypes.GettableSpanMapperGroup `json:"data"`
|
|
}
|
|
|
|
// O11ySpanMappersOut is one group's mappers.
|
|
type O11ySpanMappersOut struct {
|
|
// Status is "success".
|
|
Status string `json:"status"`
|
|
// Data holds the mappers.
|
|
Data spantypes.GettableSpanMappers `json:"data"`
|
|
}
|
|
|
|
// O11ySpanMapperOut is one mapper.
|
|
type O11ySpanMapperOut struct {
|
|
// Status is "success".
|
|
Status string `json:"status"`
|
|
// Data is the mapper.
|
|
Data spantypes.GettableSpanMapper `json:"data"`
|
|
}
|