1
2
3
4
5
6
7 package config
8
9 import (
10 "encoding/json"
11 "os"
12 "strings"
13
14 "golang.org/x/telemetry/internal/telemetry"
15 )
16
17
18
19 type Config struct {
20 *telemetry.UploadConfig
21 program map[string]bool
22 goos map[string]bool
23 goarch map[string]bool
24 goversion map[string]bool
25 pgversion map[pgkey]bool
26 pgcounter map[pgkey]bool
27 pgcounterprefix map[pgkey]bool
28 pgstack map[pgkey]bool
29 rate map[pgkey]float64
30 }
31
32 type pgkey struct {
33 program, key string
34 }
35
36 func ReadConfig(file string) (*Config, error) {
37 data, err := os.ReadFile(file)
38 if err != nil {
39 return nil, err
40 }
41 var cfg telemetry.UploadConfig
42 if err := json.Unmarshal(data, &cfg); err != nil {
43 return nil, err
44 }
45 return NewConfig(&cfg), nil
46 }
47
48 func NewConfig(cfg *telemetry.UploadConfig) *Config {
49 ucfg := Config{UploadConfig: cfg}
50 ucfg.goos = set(ucfg.GOOS)
51 ucfg.goarch = set(ucfg.GOARCH)
52 ucfg.goversion = set(ucfg.GoVersion)
53 ucfg.program = make(map[string]bool, len(ucfg.Programs))
54 ucfg.pgversion = make(map[pgkey]bool, len(ucfg.Programs))
55 ucfg.pgcounter = make(map[pgkey]bool, len(ucfg.Programs))
56 ucfg.pgcounterprefix = make(map[pgkey]bool, len(ucfg.Programs))
57 ucfg.pgstack = make(map[pgkey]bool, len(ucfg.Programs))
58 ucfg.rate = make(map[pgkey]float64)
59 for _, p := range ucfg.Programs {
60 ucfg.program[p.Name] = true
61 for _, v := range p.Versions {
62 ucfg.pgversion[pgkey{p.Name, v}] = true
63 }
64 for _, c := range p.Counters {
65 for _, e := range Expand(c.Name) {
66 ucfg.pgcounter[pgkey{p.Name, e}] = true
67 ucfg.rate[pgkey{p.Name, e}] = c.Rate
68 }
69 prefix, _, found := strings.Cut(c.Name, ":")
70 if found {
71 ucfg.pgcounterprefix[pgkey{p.Name, prefix}] = true
72 }
73 }
74 for _, s := range p.Stacks {
75 ucfg.pgstack[pgkey{p.Name, s.Name}] = true
76 ucfg.rate[pgkey{p.Name, s.Name}] = s.Rate
77 }
78 }
79 return &ucfg
80 }
81
82 func (r *Config) HasProgram(s string) bool {
83 return r.program[s]
84 }
85
86 func (r *Config) HasGOOS(s string) bool {
87 return r.goos[s]
88 }
89
90 func (r *Config) HasGOARCH(s string) bool {
91 return r.goarch[s]
92 }
93
94 func (r *Config) HasGoVersion(s string) bool {
95 return r.goversion[s]
96 }
97
98 func (r *Config) HasVersion(program, version string) bool {
99 return r.pgversion[pgkey{program, version}]
100 }
101
102 func (r *Config) HasCounter(program, counter string) bool {
103 return r.pgcounter[pgkey{program, counter}]
104 }
105
106 func (r *Config) HasCounterPrefix(program, prefix string) bool {
107 return r.pgcounterprefix[pgkey{program, prefix}]
108 }
109
110 func (r *Config) HasStack(program, stack string) bool {
111 return r.pgstack[pgkey{program, stack}]
112 }
113
114 func (r *Config) Rate(program, name string) float64 {
115 return r.rate[pgkey{program, name}]
116 }
117
118 func set(slice []string) map[string]bool {
119 s := make(map[string]bool, len(slice))
120 for _, v := range slice {
121 s[v] = true
122 }
123 return s
124 }
125
126
127
128 func Expand(counter string) []string {
129 prefix, rest, hasBuckets := strings.Cut(counter, "{")
130 var counters []string
131 if hasBuckets {
132 buckets := strings.Split(strings.TrimSuffix(rest, "}"), ",")
133 for _, b := range buckets {
134 counters = append(counters, prefix+b)
135 }
136 } else {
137 counters = append(counters, prefix)
138 }
139 return counters
140 }
141
View as plain text