-
Notifications
You must be signed in to change notification settings - Fork 3
/
profile.go
146 lines (127 loc) · 3.74 KB
/
profile.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package cmd
import (
"errors"
"fmt"
"net/url"
"time"
"github.com/grafana/pyroscope-go"
"github.com/hamba/logger/v2"
"github.com/urfave/cli/v2"
)
var allProfilingTypes = []pyroscope.ProfileType{
pyroscope.ProfileCPU,
pyroscope.ProfileInuseObjects,
pyroscope.ProfileAllocObjects,
pyroscope.ProfileInuseSpace,
pyroscope.ProfileAllocSpace,
pyroscope.ProfileGoroutines,
pyroscope.ProfileMutexCount,
pyroscope.ProfileMutexDuration,
pyroscope.ProfileBlockCount,
pyroscope.ProfileBlockDuration,
}
// Tracing flag constants declared for CLI use.
const (
FlagProfilingDSN = "profiling.dsn"
FlagProfileUploadRate = "profiling.upload-rate"
FlagProfilingTags = "profiling.tags"
FlagProfilingTypes = "profiling.types"
)
// CategoryProfiling is the profiling category.
const CategoryProfiling = "Profiling"
// ProfilingFlags are flags that configure profiling.
var ProfilingFlags = Flags{
&cli.StringFlag{
Name: FlagProfilingDSN,
Category: CategoryProfiling,
Usage: "The address to the Pyroscope server, in the format: " +
"'http://basic:auth@server:port?token=auth-token&tenantid=tenant-id'.",
EnvVars: []string{"PROFILING_DSN"},
},
&cli.DurationFlag{
Name: FlagProfileUploadRate,
Category: CategoryProfiling,
Usage: "The rate at which profiles are uploaded.",
Value: 15 * time.Second,
EnvVars: []string{"PROFILING_UPLOAD_RATE"},
},
&cli.StringSliceFlag{
Name: FlagProfilingTags,
Category: CategoryProfiling,
Usage: "A list of tags appended to every profile. Format: key=value.",
EnvVars: []string{"PROFILING_TAGS"},
},
&cli.StringSliceFlag{
Name: FlagProfilingTypes,
Category: CategoryProfiling,
Usage: "The type of profiles to include. Defaults to all.",
EnvVars: []string{"PROFILING_TYPES"},
},
}
// NewProfiler returns a profiler configured from the cli.
// If no profiler is configured, nil is returned.
func NewProfiler(c *cli.Context, svc string, log *logger.Logger) (*pyroscope.Profiler, error) {
dsn := c.String(FlagProfilingDSN)
if dsn == "" {
//nolint:nilnil // There is no sentinel in this case.
return nil, nil
}
u, err := url.Parse(dsn)
if err != nil {
return nil, fmt.Errorf("parsing profiling DSN: %w", err)
}
tenantID := u.Query().Get("tenantid")
authToken := u.Query().Get("token")
var username, password string
if u.User != nil {
username = u.User.Username()
password, _ = u.User.Password()
}
if (username != "" || password != "") && authToken != "" {
return nil, errors.New("cannot set auth token and basic auth")
}
srvURL := &url.URL{
Scheme: u.Scheme,
Host: u.Host,
Path: u.Path,
}
var tags map[string]string
if pairs := c.StringSlice(FlagProfilingTags); len(pairs) > 0 {
tags, err = sliceToMap(pairs)
if err != nil {
return nil, err
}
}
types := allProfilingTypes
if newTypes := c.StringSlice(FlagProfilingTypes); len(newTypes) > 0 {
types = make([]pyroscope.ProfileType, len(newTypes))
for i, typ := range newTypes {
types[i] = pyroscope.ProfileType(typ)
}
}
cfg := pyroscope.Config{
ApplicationName: svc,
Tags: tags,
ServerAddress: srvURL.String(),
AuthToken: authToken,
BasicAuthUser: username,
BasicAuthPassword: password,
TenantID: tenantID,
UploadRate: c.Duration(FlagProfileUploadRate),
Logger: pyroLogAdapter{log: log},
ProfileTypes: types,
}
return pyroscope.Start(cfg)
}
type pyroLogAdapter struct {
log *logger.Logger
}
func (a pyroLogAdapter) Infof(format string, args ...any) {
a.log.Info(fmt.Sprintf(format, args...))
}
func (a pyroLogAdapter) Debugf(format string, args ...any) {
a.log.Trace(fmt.Sprintf(format, args...))
}
func (a pyroLogAdapter) Errorf(format string, args ...any) {
a.log.Error(fmt.Sprintf(format, args...))
}