mirror of
https://github.com/hanzoai/telemetry.git
synced 2026-10-30 20:01:49 +00:00
#### Description Move some reusable modules to an internal package. Those modules can be used by `schemagen` and `ocb` to generate a big schema that users can use to validate OpenTelemetry Collector configuations. <!-- Issue number if applicable --> #### Link to tracking issue Updates #15010 --------- Signed-off-by: Israel Blancas <[email protected]>
216 lines
4.4 KiB
Go
216 lines
4.4 KiB
Go
// Copyright The OpenTelemetry Authors
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package schemagen // import "go.opentelemetry.io/collector/internal/schemagen"
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"maps"
|
|
"path"
|
|
"regexp"
|
|
"slices"
|
|
"strings"
|
|
|
|
"golang.org/x/mod/module"
|
|
)
|
|
|
|
var namespaceToURL = map[string]string{
|
|
"go.opentelemetry.io/collector": "https://raw.githubusercontent.com/open-telemetry/opentelemetry-collector",
|
|
"github.com/open-telemetry/opentelemetry-collector-contrib": "https://raw.githubusercontent.com/open-telemetry/opentelemetry-collector-contrib",
|
|
}
|
|
|
|
var supportedNamespaces = slices.Collect(maps.Keys(namespaceToURL))
|
|
|
|
type RefKind int
|
|
|
|
const (
|
|
External RefKind = iota
|
|
Internal
|
|
Local
|
|
)
|
|
|
|
type Ref struct {
|
|
namespace string
|
|
schemaID string
|
|
defName string
|
|
kind RefKind
|
|
}
|
|
|
|
var localRefPattern = regexp.MustCompile(`^((?:/|\.\.?/).*?)(?:\.([^./]+))?$`)
|
|
|
|
func NewRef(refPath string) *Ref {
|
|
var namespace, schemaID, defName string
|
|
var kind RefKind
|
|
|
|
switch {
|
|
case localRefPattern.MatchString(refPath):
|
|
matches := localRefPattern.FindStringSubmatch(refPath)
|
|
schemaID = matches[1]
|
|
defName = matches[2]
|
|
kind = Local
|
|
case !strings.ContainsRune(refPath, '/'):
|
|
defName = refPath
|
|
kind = Internal
|
|
default:
|
|
namespace = namespaceOf(refPath)
|
|
rest, _ := strings.CutPrefix(refPath, namespace)
|
|
schemaID, defName, _ = strings.Cut(rest, ".")
|
|
schemaID = strings.Trim(schemaID, "/")
|
|
kind = External
|
|
}
|
|
|
|
return &Ref{
|
|
namespace: namespace,
|
|
schemaID: schemaID,
|
|
defName: defName,
|
|
kind: kind,
|
|
}
|
|
}
|
|
|
|
func WithOrigin(refPath string, origin *Ref) *Ref {
|
|
ref := NewRef(refPath)
|
|
if origin == nil {
|
|
return ref
|
|
}
|
|
|
|
if origin.IsExternal() {
|
|
ref.namespace = origin.namespace
|
|
ref.kind = External
|
|
if strings.HasPrefix(ref.schemaID, "/") {
|
|
ref.schemaID = strings.Trim(ref.schemaID, "/")
|
|
return ref
|
|
}
|
|
|
|
ref.schemaID = path.Join(origin.schemaID, ref.schemaID)
|
|
return ref
|
|
}
|
|
// check if it's a local ref with relative path, if so, resolve it against the origin schema ID
|
|
if ref.IsLocal() && !strings.HasPrefix(ref.schemaID, "/") {
|
|
ref.schemaID = path.Join(origin.schemaID, ref.schemaID)
|
|
}
|
|
return ref
|
|
}
|
|
|
|
func namespaceOf(path string) string {
|
|
if ns, ok := matchSupportedNamespace(path); ok {
|
|
return ns
|
|
}
|
|
if idx := strings.LastIndex(path, "/"); idx != -1 {
|
|
return path[:idx]
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func matchSupportedNamespace(path string) (string, bool) {
|
|
for _, ns := range supportedNamespaces {
|
|
if strings.HasPrefix(path, ns) {
|
|
return ns, true
|
|
}
|
|
}
|
|
return "", false
|
|
}
|
|
|
|
func (r *Ref) Namespace() (string, bool) {
|
|
_, ok := matchSupportedNamespace(r.namespace)
|
|
return r.namespace, ok
|
|
}
|
|
|
|
func (r *Ref) Module() string {
|
|
if r.namespace != "" {
|
|
return r.namespace + "/" + r.schemaID
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func (r *Ref) SchemaID() string {
|
|
return r.schemaID
|
|
}
|
|
|
|
func (r *Ref) DefName() string {
|
|
return r.defName
|
|
}
|
|
|
|
func (r *Ref) URL(version string) (string, error) {
|
|
ns, ok := r.Namespace()
|
|
if !ok {
|
|
return "", errors.New("unsupported namespace")
|
|
}
|
|
baseURL := namespaceToURL[ns]
|
|
version = rawRefVersion(version)
|
|
|
|
return fmt.Sprintf("%s/%s/%s/%s",
|
|
baseURL,
|
|
version,
|
|
r.SchemaID(),
|
|
schemaFileName),
|
|
nil
|
|
}
|
|
|
|
func rawRefVersion(version string) string {
|
|
trimmedVersion, _, _ := strings.Cut(version, "+")
|
|
if rev, err := module.PseudoVersionRev(trimmedVersion); err == nil {
|
|
return rev
|
|
}
|
|
return trimmedVersion
|
|
}
|
|
|
|
func (r *Ref) IsInternal() bool {
|
|
return r.kind == Internal
|
|
}
|
|
|
|
func (r *Ref) IsLocal() bool {
|
|
return r.kind == Local
|
|
}
|
|
|
|
func (r *Ref) IsExternal() bool {
|
|
return r.kind == External
|
|
}
|
|
|
|
func (r *Ref) Validate() error {
|
|
if r.String() == "" {
|
|
return errors.New("empty path")
|
|
}
|
|
|
|
if r.defName == "" {
|
|
return errors.New("missing definition name")
|
|
}
|
|
if r.IsLocal() && r.schemaID == "" {
|
|
return errors.New("missing schema ID in local reference")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (r *Ref) String() string {
|
|
var sb strings.Builder
|
|
if r.namespace != "" {
|
|
sb.WriteString(r.namespace)
|
|
}
|
|
if r.schemaID != "" {
|
|
if sb.Len() > 0 {
|
|
sb.WriteRune('/')
|
|
}
|
|
sb.WriteString(r.schemaID)
|
|
}
|
|
if r.defName != "" {
|
|
if sb.Len() > 0 {
|
|
sb.WriteRune('.')
|
|
}
|
|
sb.WriteString(r.defName)
|
|
}
|
|
|
|
return sb.String()
|
|
}
|
|
|
|
func (r *Ref) CacheKey() string {
|
|
return r.String()
|
|
}
|
|
|
|
func LocalizeRef(refPath, importRootPath string) string {
|
|
if importRootPath == "" || !strings.HasPrefix(refPath, importRootPath+"/") {
|
|
return refPath
|
|
}
|
|
return strings.TrimPrefix(refPath, importRootPath)
|
|
}
|