Skip to content
This repository was archived by the owner on Nov 7, 2022. It is now read-only.

Commit bad985a

Browse files
author
Paulo Janotti
authored
Add optional net/http/pprof support (#432)
* Add optional net/http/pprof support Add a command-line flag to enable net/http/pprof. This is the standard golang profiler and having it available is an easy way to collect cpu/mem profile from users that may face such issues. Opportunistic fix add SIGTERM for proper k8s shutdown. Update demo to expose pprof endpoints * Remove ocagent/cli.go and use viper for pprof setup
1 parent 4fdfb60 commit bad985a

8 files changed

Lines changed: 167 additions & 103 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@ Flags:
357357
--debug-processor Flag to add a debug processor (combine with log level DEBUG to log incoming spans)
358358
--health-check-http-port uint Port on which to run the healthcheck http server. (default 13133)
359359
-h, --help help for occollector
360+
--http-pprof-port uint Port to be used by golang net/http/pprof (Performance Profiler), the profiler is disabled if no port or 0 is specified.
360361
--log-level string Output level of logs (TRACE, DEBUG, INFO, WARN, ERROR, FATAL) (default "INFO")
361362
--metrics-level string Output level of telemetry metrics (NONE, BASIC, NORMAL, DETAILED) (default "BASIC")
362363
--metrics-port uint Port exposing collector telemetry. (default 8888)

cmd/ocagent/cli.go

Lines changed: 0 additions & 45 deletions
This file was deleted.

cmd/ocagent/main.go

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ import (
2525
"net/http"
2626
"os"
2727
"os/signal"
28+
"syscall"
2829

30+
"github.com/spf13/cobra"
31+
"github.com/spf13/viper"
2932
"go.opencensus.io/stats/view"
3033
"go.opencensus.io/zpages"
3134
"go.uber.org/zap"
@@ -34,6 +37,8 @@ import (
3437
"github.com/census-instrumentation/opencensus-service/internal"
3538
"github.com/census-instrumentation/opencensus-service/internal/config"
3639
"github.com/census-instrumentation/opencensus-service/internal/config/viperutils"
40+
"github.com/census-instrumentation/opencensus-service/internal/pprofserver"
41+
"github.com/census-instrumentation/opencensus-service/internal/version"
3742
"github.com/census-instrumentation/opencensus-service/processor"
3843
"github.com/census-instrumentation/opencensus-service/receiver/jaegerreceiver"
3944
"github.com/census-instrumentation/opencensus-service/receiver/opencensusreceiver"
@@ -42,10 +47,31 @@ import (
4247
"github.com/census-instrumentation/opencensus-service/receiver/zipkinreceiver/scribe"
4348
)
4449

50+
var rootCmd = &cobra.Command{
51+
Use: "ocagent",
52+
Short: "ocagent runs the OpenCensus service",
53+
Run: func(cmd *cobra.Command, args []string) {
54+
runOCAgent()
55+
},
56+
}
57+
58+
var viperCfg = viper.New()
59+
4560
var configYAMLFile string
46-
var ocReceiverPort int
4761

48-
const zipkinRoute = "/api/v2/spans"
62+
func init() {
63+
var versionCmd = &cobra.Command{
64+
Use: "version",
65+
Short: "Print the version information for ocagent",
66+
Run: func(cmd *cobra.Command, args []string) {
67+
fmt.Print(version.Info())
68+
},
69+
}
70+
rootCmd.AddCommand(versionCmd)
71+
rootCmd.PersistentFlags().StringVarP(&configYAMLFile, "config", "c", "config.yaml", "The YAML file with the configurations for the agent and various exporters")
72+
73+
viperutils.AddFlags(viperCfg, rootCmd, pprofserver.AddFlags)
74+
}
4975

5076
func main() {
5177
if err := rootCmd.Execute(); err != nil {
@@ -78,12 +104,19 @@ func runOCAgent() {
78104
log.Fatalf("Could not instantiate logger: %v", err)
79105
}
80106

107+
var asyncErrorChan = make(chan error)
108+
err = pprofserver.SetupFromViper(asyncErrorChan, viperCfg, logger)
109+
if err != nil {
110+
log.Fatalf("Failed to start net/http/pprof: %v", err)
111+
}
112+
81113
// TODO(skaris): move the rest of the configs to use viper
82-
v, err := viperutils.ViperFromYAMLBytes([]byte(yamlBlob))
114+
err = viperutils.LoadYAMLBytes(viperCfg, []byte(yamlBlob))
83115
if err != nil {
84116
log.Fatalf("Config: failed to create viper from YAML: %v", err)
85117
}
86-
traceExporters, metricsExporters, closeFns, err := config.ExportersFromViperConfig(logger, v)
118+
119+
traceExporters, metricsExporters, closeFns, err := config.ExportersFromViperConfig(logger, viperCfg)
87120
if err != nil {
88121
log.Fatalf("Config: failed to create exporters from YAML: %v", err)
89122
}
@@ -150,11 +183,15 @@ func runOCAgent() {
150183
}
151184
}()
152185

153-
signalsChan := make(chan os.Signal)
154-
signal.Notify(signalsChan, os.Interrupt)
186+
signalsChan := make(chan os.Signal, 1)
187+
signal.Notify(signalsChan, os.Interrupt, syscall.SIGTERM)
155188

156-
// Wait for the closing signal
157-
<-signalsChan
189+
select {
190+
case err = <-asyncErrorChan:
191+
log.Fatalf("Asynchronous error %q, terminating process", err)
192+
case s := <-signalsChan:
193+
log.Printf("Received %q signal from OS, terminating process", s)
194+
}
158195
}
159196

160197
func runZPages(port int) func() error {

cmd/occollector/app/collector/collector.go

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ import (
3030

3131
"github.com/census-instrumentation/opencensus-service/cmd/occollector/app/builder"
3232
"github.com/census-instrumentation/opencensus-service/internal/collector/processor"
33+
"github.com/census-instrumentation/opencensus-service/internal/config/viperutils"
34+
"github.com/census-instrumentation/opencensus-service/internal/pprofserver"
3335
"github.com/census-instrumentation/opencensus-service/receiver"
3436
)
3537

@@ -70,13 +72,15 @@ func (app *Application) init() {
7072
}
7173

7274
func (app *Application) execute() {
73-
var asyncErrorChannel = make(chan error)
74-
var signalsChannel = make(chan os.Signal)
75-
signal.Notify(signalsChannel, os.Interrupt, syscall.SIGTERM)
75+
asyncErrorChannel := make(chan error)
7676

7777
app.logger.Info("Starting...", zap.Int("NumCPU", runtime.NumCPU()))
7878

79-
var err error
79+
err := pprofserver.SetupFromViper(asyncErrorChannel, app.v, app.logger)
80+
if err != nil {
81+
log.Fatalf("Failed to start net/http/pprof: %v", err)
82+
}
83+
8084
app.healthCheck, err = newHealthCheck(app.v, app.logger)
8185
if err != nil {
8286
log.Fatalf("Failed to start healthcheck server: %v", err)
@@ -93,14 +97,17 @@ func (app *Application) execute() {
9397
os.Exit(1)
9498
}
9599

100+
signalsChannel := make(chan os.Signal, 1)
101+
signal.Notify(signalsChannel, os.Interrupt, syscall.SIGTERM)
102+
96103
// mark service as ready to receive traffic.
97104
app.healthCheck.Ready()
98105

99106
select {
100107
case err = <-asyncErrorChannel:
101108
app.logger.Error("Asynchronous error received, terminating process", zap.Error(err))
102-
case <-signalsChannel:
103-
app.logger.Info("Received kill signal from OS")
109+
case s := <-signalsChannel:
110+
app.logger.Info("Received signal from OS", zap.String("signal", s.String()))
104111
}
105112

106113
app.healthCheck.Set(healthcheck.Unavailable)
@@ -131,11 +138,12 @@ func (app *Application) Start() error {
131138
app.execute()
132139
},
133140
}
134-
addFlags(app.v, rootCmd,
141+
viperutils.AddFlags(app.v, rootCmd,
135142
telemetryFlags,
136143
builder.Flags,
137144
healthCheckFlags,
138145
loggerFlags,
146+
pprofserver.AddFlags,
139147
)
140148

141149
return rootCmd.Execute()

cmd/occollector/app/collector/flags.go

Lines changed: 0 additions & 37 deletions
This file was deleted.

demos/trace/docker-compose.yaml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@ services:
1717
# Collector
1818
oc-collector:
1919
image: occollector:latest
20-
command: ["--config=/etc/oc-collector-config.yaml"]
20+
command: ["--config=/etc/oc-collector-config.yaml", "--http-pprof-port=1777"]
2121
volumes:
2222
- ./oc-collector-config.yaml:/etc/oc-collector-config.yaml
2323
ports:
2424
- "55678"
25+
- "1777:1777"
2526
- "8888:8888" # Prometheus metrics
2627
depends_on:
2728
- jaeger-all-in-one
@@ -30,18 +31,19 @@ services:
3031
# Agent
3132
oc-agent:
3233
image: ocagent:latest
33-
command: ["--config=/etc/oc-agent-config.yaml"]
34+
command: ["--config=/etc/oc-agent-config.yaml", "--http-pprof-port=1888"]
3435
volumes:
3536
- ./oc-agent-config.yaml:/etc/oc-agent-config.yaml
3637
ports:
38+
- "1888:1888"
3739
- "14268"
3840
- "55678"
3941
depends_on:
4042
- oc-collector
4143

4244
# Synthetic load generator
4345
synthetic-load-generator:
44-
image: omnition/synthetic-load-generator:1.0.6
46+
image: omnition/synthetic-load-generator:1.0.25
4547
environment:
4648
- JAEGER_COLLECTOR_URL=http://oc-agent:14268
4749
depends_on:
Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,60 @@
1+
// Copyright 2019, OpenCensus Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
// Package sampling containts the interfaces and data types used to implement
16+
// the various sampling policies.
17+
118
package viperutils
219

320
import (
421
"bytes"
22+
"flag"
23+
"strings"
524

25+
"github.com/spf13/cobra"
626
"github.com/spf13/viper"
727
)
828

929
// ViperFromYAMLBytes unmarshals byte content in the YAML file format into
10-
// a viper object
30+
// a viper object.
1131
func ViperFromYAMLBytes(yamlBlob []byte) (*viper.Viper, error) {
1232
v := viper.New()
13-
v.SetConfigType("yaml")
14-
if err := v.ReadConfig(bytes.NewBuffer(yamlBlob)); err != nil {
33+
if err := LoadYAMLBytes(v, yamlBlob); err != nil {
1534
return nil, err
1635
}
1736
return v, nil
1837
}
38+
39+
// LoadYAMLBytes sets the viper config type to yaml and loads the given blob.
40+
func LoadYAMLBytes(v *viper.Viper, yamlBlob []byte) error {
41+
v.SetConfigType("yaml")
42+
if err := v.ReadConfig(bytes.NewBuffer(yamlBlob)); err != nil {
43+
return err
44+
}
45+
return nil
46+
}
47+
48+
// AddFlags adds the provided flags to the provided viper and cobra command.
49+
func AddFlags(v *viper.Viper, command *cobra.Command, addFlagsFns ...func(*flag.FlagSet)) (*viper.Viper, *cobra.Command) {
50+
flagSet := new(flag.FlagSet)
51+
for _, addFlags := range addFlagsFns {
52+
addFlags(flagSet)
53+
}
54+
command.Flags().AddGoFlagSet(flagSet)
55+
56+
v.AutomaticEnv()
57+
v.SetEnvKeyReplacer(strings.NewReplacer("-", "_", ".", "_"))
58+
v.BindPFlags(command.Flags())
59+
return v, command
60+
}

0 commit comments

Comments
 (0)