diff --git a/agent/agent.go b/agent/agent.go index ae75c340..1f169eb1 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -19,7 +19,7 @@ import ( "github.com/mitchellh/go-homedir" "github.com/opentracing/opentracing-go" - "go.undefinedlabs.com/scopeagent/env" + "go.undefinedlabs.com/scopeagent/config" scopeError "go.undefinedlabs.com/scopeagent/errors" "go.undefinedlabs.com/scopeagent/instrumentation" scopetesting "go.undefinedlabs.com/scopeagent/instrumentation/testing" @@ -66,6 +66,8 @@ var ( testingModeFrequency = time.Second nonTestingModeFrequency = time.Minute + + cfg = config.Get() ) func WithApiKey(apiKey string) Option { @@ -210,13 +212,13 @@ func NewAgent(options ...Option) (*Agent, error) { agent.logger = log.New(ioutil.Discard, "", 0) } - agent.debugMode = agent.debugMode || env.ScopeDebug.Value + agent.debugMode = agent.debugMode || *cfg.Debug configProfile := GetConfigCurrentProfile() if agent.apiKey == "" || agent.apiEndpoint == "" { - if dsn, set := env.ScopeDsn.Tuple(); set && dsn != "" { - dsnApiKey, dsnApiEndpoint, dsnErr := parseDSN(dsn) + if cfg.Dsn != nil && *cfg.Dsn != "" { + dsnApiKey, dsnApiEndpoint, dsnErr := parseDSN(*cfg.Dsn) if dsnErr != nil { agent.logger.Printf("Error parsing dsn value: %v\n", dsnErr) } else { @@ -229,8 +231,8 @@ func NewAgent(options ...Option) (*Agent, error) { } if agent.apiKey == "" { - if apiKey, set := env.ScopeApiKey.Tuple(); set && apiKey != "" { - agent.apiKey = apiKey + if cfg.ApiKey != nil && *cfg.ApiKey != "" { + agent.apiKey = *cfg.ApiKey } else if configProfile != nil { agent.logger.Println("API key found in the native app configuration") agent.apiKey = configProfile.ApiKey @@ -242,12 +244,13 @@ func NewAgent(options ...Option) (*Agent, error) { } if agent.apiEndpoint == "" { - if endpoint, set := env.ScopeApiEndpoint.Tuple(); set && endpoint != "" { - agent.apiEndpoint = endpoint + if cfg.ApiEndpoint != nil && *cfg.ApiEndpoint != "" { + agent.apiEndpoint = *cfg.ApiEndpoint } else if configProfile != nil { agent.logger.Println("API endpoint found in the native app configuration") agent.apiEndpoint = configProfile.ApiEndpoint } else { + endpoint := "https://app.scope.dev" agent.logger.Printf("using default endpoint: %v\n", endpoint) agent.apiEndpoint = endpoint } @@ -287,13 +290,19 @@ func NewAgent(options ...Option) (*Agent, error) { agent.metadata[tags.GoVersion] = runtime.Version() // Service name - addElementToMapIfEmpty(agent.metadata, tags.Service, env.ScopeService.Value) + if cfg.Service != nil { + addElementToMapIfEmpty(agent.metadata, tags.Service, *cfg.Service) + } // Configurations - addElementToMapIfEmpty(agent.metadata, tags.ConfigurationKeys, env.ScopeConfiguration.Value) + if cfg.Configuration != nil { + addElementToMapIfEmpty(agent.metadata, tags.ConfigurationKeys, cfg.Configuration) + } // Metadata - addToMapIfEmpty(agent.metadata, env.ScopeMetadata.Value) + if cfg.Metadata != nil { + addToMapIfEmpty(agent.metadata, cfg.Metadata) + } // Git data addToMapIfEmpty(agent.metadata, getGitInfoFromEnv()) @@ -323,17 +332,19 @@ func NewAgent(options ...Option) (*Agent, error) { agent.metadata[tags.SourceRoot] = sourceRoot if !agent.testingMode { - if env.ScopeTestingMode.IsSet { - agent.testingMode = env.ScopeTestingMode.Value + if cfg.TestingMode != nil { + agent.testingMode = *cfg.TestingMode } else { agent.testingMode = agent.metadata[tags.CI].(bool) } } - if agent.failRetriesCount == 0 { - agent.failRetriesCount = env.ScopeTestingFailRetries.Value + if agent.failRetriesCount == 0 && cfg.Instrumentation.TestsFrameworks.FailRetries != nil { + agent.failRetriesCount = *cfg.Instrumentation.TestsFrameworks.FailRetries + } + if cfg.Instrumentation.TestsFrameworks.PanicAsFail != nil { + agent.panicAsFail = agent.panicAsFail || *cfg.Instrumentation.TestsFrameworks.PanicAsFail } - agent.panicAsFail = agent.panicAsFail || env.ScopeTestingPanicAsFail.Value if agent.debugMode { agent.logMetadata() @@ -362,7 +373,7 @@ func NewAgent(options ...Option) (*Agent, error) { instrumentation.SetTracer(agent.tracer) instrumentation.SetLogger(agent.logger) instrumentation.SetSourceRoot(sourceRoot) - if agent.setGlobalTracer || env.ScopeTracerGlobal.Value { + if agent.setGlobalTracer || (cfg.Tracer.Global != nil && *cfg.Tracer.Global) { opentracing.SetGlobalTracer(agent.Tracer()) } @@ -457,8 +468,8 @@ func generateAgentID() string { } func getLogPath() (string, error) { - if env.ScopeLoggerRoot.IsSet { - return env.ScopeLoggerRoot.Value, nil + if cfg.Logger.Root != nil { + return *cfg.Logger.Root, nil } logFolder := "" diff --git a/agent/agent_test.go b/agent/agent_test.go index a9a420db..8242af72 100644 --- a/agent/agent_test.go +++ b/agent/agent_test.go @@ -9,7 +9,7 @@ import ( "testing" "time" - "go.undefinedlabs.com/scopeagent/env" + "go.undefinedlabs.com/scopeagent/config" "go.undefinedlabs.com/scopeagent/tags" ) @@ -134,7 +134,9 @@ func sameElements(a, b []string) bool { } func TestTildeExpandRaceMetadata(t *testing.T) { - env.ScopeSourceRoot.Value = "~/scope" + cfg := config.Get() + sroot := "~/scope" + cfg.SourceRoot = &sroot agent, err := NewAgent(WithApiKey("123"), WithTestingModeEnabled()) if err != nil { t.Fatal(err) diff --git a/agent/git.go b/agent/git.go index b66685ea..077984ff 100644 --- a/agent/git.go +++ b/agent/git.go @@ -13,7 +13,6 @@ import ( "strings" "github.com/google/uuid" - "go.undefinedlabs.com/scopeagent/env" "go.undefinedlabs.com/scopeagent/tags" ) @@ -163,6 +162,10 @@ func getGitFolder() (string, error) { } func getGitDiff() *GitDiff { + if cfg.Instrumentation.DiffSummary != nil && !*cfg.Instrumentation.DiffSummary { + return nil + } + var diff string if diffBytes, err := exec.Command("git", "diff", "--numstat").Output(); err == nil { diff = string(diffBytes) @@ -229,20 +232,20 @@ func getGitInfoFromGitFolder() map[string]interface{} { func getGitInfoFromEnv() map[string]interface{} { gitInfo := map[string]interface{}{} - if repository, set := env.ScopeRepository.Tuple(); set && repository != "" { - gitInfo[tags.Repository] = repository + if cfg.Repository != nil && *cfg.Repository != "" { + gitInfo[tags.Repository] = *cfg.Repository } - if commit, set := env.ScopeCommitSha.Tuple(); set && commit != "" { - gitInfo[tags.Commit] = commit + if cfg.CommitSha != nil && *cfg.CommitSha != "" { + gitInfo[tags.Commit] = *cfg.CommitSha } - if sourceRoot, set := env.ScopeSourceRoot.Tuple(); set && sourceRoot != "" { + if cfg.SourceRoot != nil && *cfg.SourceRoot != "" { // We check if is a valid and existing folder - if fInfo, err := os.Stat(sourceRoot); err == nil && fInfo.IsDir() { - gitInfo[tags.SourceRoot] = sourceRoot + if fInfo, err := os.Stat(*cfg.SourceRoot); err == nil && fInfo.IsDir() { + gitInfo[tags.SourceRoot] = *cfg.SourceRoot } } - if branch, set := env.ScopeBranch.Tuple(); set && branch != "" { - gitInfo[tags.Branch] = branch + if cfg.Branch != nil && *cfg.Branch != "" { + gitInfo[tags.Branch] = *cfg.Branch } return gitInfo diff --git a/agent/recorder.go b/agent/recorder.go index 400e085a..5c3f28b4 100644 --- a/agent/recorder.go +++ b/agent/recorder.go @@ -38,8 +38,10 @@ type ( debugMode bool metadata map[string]interface{} - payloadSpans []PayloadSpan - payloadEvents []PayloadEvent + payloadSpans []PayloadSpan + payloadEvents []PayloadEvent + maxSpansPerPayload int + maxEventsPerPayload int flushFrequency time.Duration url string @@ -82,6 +84,16 @@ func NewSpanRecorder(agent *Agent) *SpanRecorder { r.url = agent.getUrl("api/agent/ingest") r.client = &http.Client{} r.stats = &RecorderStats{} + if cfg.Tracer.Dispatcher.Events.MaxPayloadSize != nil { + r.maxEventsPerPayload = *cfg.Tracer.Dispatcher.Events.MaxPayloadSize + } else { + r.maxEventsPerPayload = 1000 + } + if cfg.Tracer.Dispatcher.Spans.MaxPayloadSize != nil { + r.maxSpansPerPayload = *cfg.Tracer.Dispatcher.Spans.MaxPayloadSize + } else { + r.maxSpansPerPayload = 1000 + } r.t.Go(r.loop) return r } @@ -142,11 +154,10 @@ func (r *SpanRecorder) loop() error { // Sends the spans in the buffer to Scope func (r *SpanRecorder) sendSpans() (error, bool) { atomic.AddInt64(&r.stats.sendSpansCalls, 1) - const batchSize = 1000 var lastError error for { - spans, spMore, spTotal := r.popPayloadSpan(batchSize) - events, evMore, evTotal := r.popPayloadEvents(batchSize) + spans, spMore, spTotal := r.popPayloadSpan(r.maxSpansPerPayload) + events, evMore, evTotal := r.popPayloadEvents(r.maxEventsPerPayload) payload := map[string]interface{}{ "metadata": r.metadata, diff --git a/config/types.go b/config/types.go new file mode 100644 index 00000000..5b949ba6 --- /dev/null +++ b/config/types.go @@ -0,0 +1,70 @@ +package config + +type ( + ScopeConfig struct { + Dsn *string `env:"SCOPE_DSN"` + ApiKey *string `env:"SCOPE_APIKEY"` + ApiEndpoint *string `env:"SCOPE_API_ENDPOINT"` + Service *string `yaml:"service" env:"SCOPE_SERVICE" default:"default"` + Repository *string `yaml:"repository" env:"SCOPE_REPOSITORY"` + CommitSha *string `yaml:"commit_sha" env:"SCOPE_COMMIT_SHA"` + Branch *string `yaml:"branch" env:"SCOPE_BRANCH"` + SourceRoot *string `yaml:"source_root" env:"SCOPE_SOURCE_ROOT"` + Logger LoggerConfig `yaml:"logger"` + Metadata map[string]interface{} `yaml:"metadata" env:"SCOPE_METADATA"` + Configuration []string `yaml:"configuration" env:"SCOPE_CONFIGURATION" default:"platform.name, platform.architecture, go.version"` + TestingMode *bool `yaml:"testing_mode" env:"SCOPE_TESTING_MODE" default:"false"` + Instrumentation InstrumentationConfig `yaml:"instrumentation"` + Tracer TracerConfig `yaml:"tracer"` + Debug *bool `env:"SCOPE_DEBUG" default:"false"` + ConfigPath *string + LoadError error + } + LoggerConfig struct { + Root *string `yaml:"root" env:"SCOPE_LOGGER_ROOT, SCOPE_LOG_ROOT_PATH"` + } + InstrumentationConfig struct { + DiffSummary *bool `yaml:"diff_summary" env:"SCOPE_INSTRUMENTATION_DIFF_SUMMARY" default:"true"` + TestsFrameworks InstrumentationTestsFrameworksConfig `yaml:"tests_frameworks"` + DB InstrumentationDatabaseConfig `yaml:"db"` + Http InstrumentationHttpConfig `yaml:"http"` + Logger InstrumentationLoggerConfig `yaml:"logger"` + } + InstrumentationTestsFrameworksConfig struct { + FailRetries *int `yaml:"fail_retries" env:"SCOPE_INSTRUMENTATION_TESTS_FRAMEWORKS_FAIL_RETRIES" default:"0"` + PanicAsFail *bool `yaml:"panic_as_fail" env:"SCOPE_INSTRUMENTATION_TESTS_FRAMEWORKS_PANIC_AS_FAIL" default:"false"` + } + InstrumentationDatabaseConfig struct { + StatementValues *bool `yaml:"statement_values" env:"SCOPE_INSTRUMENTATION_DB_STATEMENT_VALUES" default:"false"` + Stacktrace *bool `yaml:"stacktrace" env:"SCOPE_INSTRUMENTATION_DB_STACKTRACE" default:"false"` + } + InstrumentationHttpConfig struct { + Client *bool `yaml:"client" env:"SCOPE_INSTRUMENTATION_HTTP_CLIENT" default:"true"` + Server *bool `yaml:"server" env:"SCOPE_INSTRUMENTATION_HTTP_SERVER" default:"true"` + Payloads *bool `yaml:"payloads" env:"SCOPE_INSTRUMENTATION_HTTP_PAYLOADS" default:"false"` + Stacktrace *bool `yaml:"stacktrace" env:"SCOPE_INSTRUMENTATION_HTTP_STACKTRACE" default:"false"` + Headers []string `yaml:"headers" env:"SCOPE_INSTRUMENTATION_HTTP_HEADERS"` + } + InstrumentationLoggerConfig struct { + StandardLogger *bool `yaml:"standard_logger" env:"SCOPE_INSTRUMENTATION_LOGGER_STANDARD_LOGGER" default:"true"` + StandardOutput *bool `yaml:"standard_output" env:"SCOPE_INSTRUMENTATION_LOGGER_STANDARD_OUTPUT" default:"false"` + StandardError *bool `yaml:"standard_error" env:"SCOPE_INSTRUMENTATION_LOGGER_STANDARD_ERROR" default:"false"` + } + TracerConfig struct { + Global *bool `yaml:"global" env:"SCOPE_TRACER_GLOBAL, SCOPE_SET_GLOBAL_TRACER" default:"false"` + Dispatcher TracerDispatcherConfig `yaml:"dispatcher"` + } + TracerDispatcherConfig struct { + HealthCheckFrequency *int `yaml:"healthcheck_frecuency" env:"SCOPE_TRACER_DISPATCHER_HEALTHCHECK_FRECUENCY" default:"1000"` + HealthCheckFrequencyInTestMode *int `yaml:"healthcheck_frecuency_in_testmode" env:"SCOPE_TRACER_DISPATCHER_HEALTHCHECK_FRECUENCY_IN_TESTMODE" default:"60000"` + ConcurrencyLevel *int `yaml:"concurrency_level" env:"SCOPE_TRACER_DISPATCHER_CONCURRENCY_LEVEL" default:"1"` + Spans TracerDispatcherSpansConfig `yaml:"spans"` + Events TracerDispatcherEventsConfig `yaml:"events"` + } + TracerDispatcherSpansConfig struct { + MaxPayloadSize *int `yaml:"max_payload_size" env:"SCOPE_TRACER_DISPATCHER_SPANS_MAX_PAYLOAD_SIZE" default:"1000"` + } + TracerDispatcherEventsConfig struct { + MaxPayloadSize *int `yaml:"max_payload_size" env:"SCOPE_TRACER_DISPATCHER_EVENTS_MAX_PAYLOAD_SIZE" default:"1000"` + } +) diff --git a/config/vars.go b/config/vars.go new file mode 100644 index 00000000..cbd96f6a --- /dev/null +++ b/config/vars.go @@ -0,0 +1,81 @@ +package config + +import ( + "errors" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "sync" + + "gopkg.in/yaml.v2" + + "github.com/undefinedlabs/go-env" +) + +var ( + current *ScopeConfig + m sync.RWMutex +) + +func Get() *ScopeConfig { + // We check is already loaded with a reader lock + m.RLock() + if current != nil { + defer m.RUnlock() + return current + } + m.RUnlock() + + // Is not loaded we block to load it + m.Lock() + defer m.Unlock() + if current != nil { + return current + } + var config ScopeConfig + content, path, err := readConfigurationFile() + if err == nil { + config.ConfigPath = path + _ = yaml.Unmarshal(content, &config) + if config.Metadata != nil { + for k, v := range config.Metadata { + if str, ok := v.(string); ok { + config.Metadata[k] = os.ExpandEnv(str) + } + } + } + } else { + config.LoadError = err + } + _, err = env.UnmarshalFromEnviron(&config) + if err != nil { + config.LoadError = err + } + current = &config + return current +} + +func readConfigurationFile() ([]byte, *string, error) { + dir, err := os.Getwd() + if err != nil { + return nil, nil, err + } + for { + rel, _ := filepath.Rel("/", dir) + // Exit the loop once we reach the basePath. + if rel == "." { + break + } + + path := fmt.Sprintf("%v/scope.yml", dir) + dat, err := ioutil.ReadFile(path) + if err == nil { + return dat, &path, nil + } + + // Going up! + dir += "/.." + } + return nil, nil, errors.New("configuration not found") +} diff --git a/env/types.go b/env/types.go deleted file mode 100644 index fe395bda..00000000 --- a/env/types.go +++ /dev/null @@ -1,148 +0,0 @@ -package env - -import ( - "fmt" - "os" - "strconv" - "strings" -) - -type ( - eVar struct { - Key string - Raw string - IsSet bool - } - - BooleanEnvVar struct { - eVar - Value bool - } - - IntEnvVar struct { - eVar - Value int - } - - StringEnvVar struct { - eVar - Value string - } - - SliceEnvVar struct { - eVar - Value []string - } - - MapEnvVar struct { - eVar - Value map[string]interface{} - } -) - -func newEVar(keys ...string) eVar { - var e eVar - for _, key := range keys { - value, ok := os.LookupEnv(key) - e = eVar{ - Key: key, - Raw: value, - IsSet: ok, - } - if ok { - break - } - } - return e -} - -func newBooleanEnvVar(defaultValue bool, keys ...string) BooleanEnvVar { - envVar := BooleanEnvVar{eVar: newEVar(keys...)} - if !envVar.IsSet { - envVar.Value = defaultValue - return envVar - } - value, err := strconv.ParseBool(envVar.Raw) - if err != nil { - panic(fmt.Sprintf("unable to parse %s - should be 'true' or 'false'", envVar.Key)) - } - envVar.Value = value - return envVar -} - -func newIntEnvVar(defaultValue int, keys ...string) IntEnvVar { - envVar := IntEnvVar{eVar: newEVar(keys...)} - if !envVar.IsSet { - envVar.Value = defaultValue - return envVar - } - value, err := strconv.ParseInt(envVar.Raw, 0, 0) - if err != nil { - panic(fmt.Sprintf("unable to parse %s - does not seem to be an int", envVar.Key)) - } - envVar.Value = int(value) - return envVar -} - -func newStringEnvVar(defaultValue string, keys ...string) StringEnvVar { - envVar := StringEnvVar{eVar: newEVar(keys...)} - if !envVar.IsSet { - envVar.Value = defaultValue - return envVar - } - envVar.Value = envVar.Raw - return envVar -} - -func newSliceEnvVar(defaultValue []string, keys ...string) SliceEnvVar { - envVar := SliceEnvVar{eVar: newEVar(keys...)} - if !envVar.IsSet { - envVar.Value = defaultValue - return envVar - } - val := strings.Split(envVar.Raw, ",") - for i := range val { - val[i] = strings.TrimSpace(val[i]) - } - envVar.Value = val - return envVar -} - -func newMapEnvVar(defaultValue map[string]interface{}, keys ...string) MapEnvVar { - envVar := MapEnvVar{eVar: newEVar(keys...)} - if !envVar.IsSet { - envVar.Value = defaultValue - return envVar - } - valItems := strings.Split(envVar.Raw, ",") - for i := range valItems { - valItems[i] = strings.TrimSpace(valItems[i]) - } - val := map[string]interface{}{} - for _, item := range valItems { - itemArr := strings.Split(item, "=") - if len(itemArr) == 2 { - val[itemArr[0]] = os.ExpandEnv(itemArr[1]) - } - } - envVar.Value = val - return envVar -} - -// For use in if's - -func (e *BooleanEnvVar) Tuple() (bool, bool) { - return e.Value, e.IsSet -} -func (e *IntEnvVar) Tuple() (int, bool) { - return e.Value, e.IsSet -} -func (e *StringEnvVar) Tuple() (string, bool) { - return e.Value, e.IsSet -} -func (e *SliceEnvVar) Tuple() ([]string, bool) { - return e.Value, e.IsSet -} -func (e *MapEnvVar) Tuple() (map[string]interface{}, bool) { - return e.Value, e.IsSet -} diff --git a/env/vars.go b/env/vars.go deleted file mode 100644 index bd726a20..00000000 --- a/env/vars.go +++ /dev/null @@ -1,26 +0,0 @@ -package env - -import "go.undefinedlabs.com/scopeagent/tags" - -var ( - ScopeDsn = newStringEnvVar("", "SCOPE_DSN") - ScopeApiKey = newStringEnvVar("", "SCOPE_APIKEY") - ScopeApiEndpoint = newStringEnvVar("https://app.scope.dev", "SCOPE_API_ENDPOINT") - ScopeService = newStringEnvVar("default", "SCOPE_SERVICE") - ScopeRepository = newStringEnvVar("", "SCOPE_REPOSITORY") - ScopeCommitSha = newStringEnvVar("", "SCOPE_COMMIT_SHA") - ScopeBranch = newStringEnvVar("", "SCOPE_BRANCH") - ScopeSourceRoot = newStringEnvVar("", "SCOPE_SOURCE_ROOT") - ScopeLoggerRoot = newStringEnvVar("", "SCOPE_LOGGER_ROOT", "SCOPE_LOG_ROOT_PATH") - ScopeDebug = newBooleanEnvVar(false, "SCOPE_DEBUG") - ScopeTracerGlobal = newBooleanEnvVar(false, "SCOPE_TRACER_GLOBAL", "SCOPE_SET_GLOBAL_TRACER") - ScopeTestingMode = newBooleanEnvVar(false, "SCOPE_TESTING_MODE") - ScopeTestingFailRetries = newIntEnvVar(0, "SCOPE_TESTING_FAIL_RETRIES") - ScopeTestingPanicAsFail = newBooleanEnvVar(false, "SCOPE_TESTING_PANIC_AS_FAIL") - ScopeConfiguration = newSliceEnvVar([]string{tags.PlatformName, tags.PlatformArchitecture, tags.GoVersion}, "SCOPE_CONFIGURATION") - ScopeMetadata = newMapEnvVar(nil, "SCOPE_METADATA") - ScopeInstrumentationHttpPayloads = newBooleanEnvVar(false, "SCOPE_INSTRUMENTATION_HTTP_PAYLOADS") - ScopeInstrumentationHttpStacktrace = newBooleanEnvVar(false, "SCOPE_INSTRUMENTATION_HTTP_STACKTRACE") - ScopeInstrumentationDbStatementValues = newBooleanEnvVar(false, "SCOPE_INSTRUMENTATION_DB_STATEMENT_VALUES") - ScopeInstrumentationDbStacktrace = newBooleanEnvVar(false, "SCOPE_INSTRUMENTATION_DB_STACKTRACE") -) diff --git a/go.mod b/go.mod index a990d6d7..69a4ed39 100644 --- a/go.mod +++ b/go.mod @@ -3,22 +3,25 @@ module go.undefinedlabs.com/scopeagent go 1.13 require ( - github.com/beevik/ntp v0.2.0 + github.com/beevik/ntp v0.3.0 github.com/davecgh/go-spew v1.1.1 github.com/go-errors/errors v1.0.1 github.com/gogo/protobuf v1.3.1 + github.com/golang/protobuf v1.3.5 // indirect github.com/google/uuid v1.1.1 github.com/kr/pretty v0.2.0 // indirect github.com/mitchellh/go-homedir v1.1.0 github.com/opentracing/basictracer-go v1.0.0 github.com/opentracing/opentracing-go v1.1.0 github.com/stretchr/testify v1.5.1 + github.com/undefinedlabs/go-env v0.0.0-20200302090545-7716d204149a github.com/undefinedlabs/go-mpatch v0.0.0-20200326085307-1a86426f42a6 github.com/vmihailenco/msgpack v4.0.4+incompatible - golang.org/x/net v0.0.0-20200301022130-244492dfa37a - golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 // indirect + golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e + golang.org/x/sys v0.0.0-20200406155108-e3b113bbe6a4 // indirect google.golang.org/appengine v1.6.5 // indirect google.golang.org/grpc v1.27.1 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 + gopkg.in/yaml.v2 v2.2.8 ) diff --git a/go.sum b/go.sum index e82076c1..c88f277f 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/beevik/ntp v0.2.0 h1:sGsd+kAXzT0bfVfzJfce04g+dSRfrs+tbQW8lweuYgw= -github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= +github.com/beevik/ntp v0.3.0 h1:xzVrPrE4ziasFXgBVBZJDP0Wg/KpMwk2KHJ4Ba8GrDw= +github.com/beevik/ntp v0.3.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -20,6 +20,8 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= @@ -43,13 +45,14 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1: github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/undefinedlabs/go-mpatch v0.0.0-20200122175732-0044123dbb98 h1:Z/megzdoMbuZ0H/oLmfTw92PAEfyTi1DkvAr8AUzFgw= -github.com/undefinedlabs/go-mpatch v0.0.0-20200122175732-0044123dbb98/go.mod h1:TyJZDQ/5AgyN7FSLiBJ8RO9u2c6wbtRvK827b6AVqY4= +github.com/undefinedlabs/go-env v0.0.0-20200302090545-7716d204149a h1:gTm9604PZ2i9P5ypIKcltKrk7zmg00faOwAjkfLOQnk= +github.com/undefinedlabs/go-env v0.0.0-20200302090545-7716d204149a/go.mod h1:6rizfv+i1uxF4fm4IBliMR2ngXLaaR1UANOx0Qmt70o= github.com/undefinedlabs/go-mpatch v0.0.0-20200326085307-1a86426f42a6 h1:VO1oVFjnL0fwOlwLpDqY1xhY/cfr0Ycz4aLwWM76D6k= github.com/undefinedlabs/go-mpatch v0.0.0-20200326085307-1a86426f42a6/go.mod h1:TyJZDQ/5AgyN7FSLiBJ8RO9u2c6wbtRvK827b6AVqY4= github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI= github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -59,16 +62,17 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200406155108-e3b113bbe6a4 h1:c1Sgqkh8v6ZxafNGG64r8C8UisIW2TKMJN8P86tKjr0= +golang.org/x/sys v0.0.0-20200406155108-e3b113bbe6a4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -92,9 +96,13 @@ google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 h1:yiW+nvdHb9LVqSHQBXfZCieqV4fzYhNBql77zY0ykqs= gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637/go.mod h1:BHsqpu/nsuzkT5BpiH1EMZPLyqSMM8JbIavyFACoFNk= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637/go.mod h1:BHsqpu/nsuzkT5BpiH1EMZPLyqSMM8JbIavyFACoFNk= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/init.go b/init.go index 995a00ad..73b0b3f4 100644 --- a/init.go +++ b/init.go @@ -12,6 +12,7 @@ import ( "testing" "go.undefinedlabs.com/scopeagent/agent" + "go.undefinedlabs.com/scopeagent/config" "go.undefinedlabs.com/scopeagent/instrumentation" "go.undefinedlabs.com/scopeagent/instrumentation/logging" scopetesting "go.undefinedlabs.com/scopeagent/instrumentation/testing" @@ -21,6 +22,7 @@ var ( defaultAgent *agent.Agent runningMutex sync.RWMutex running bool + cfg = config.Get() ) // Helper function to run a `testing.M` object and gracefully stopping the agent afterwards @@ -38,7 +40,15 @@ func Run(m *testing.M, opts ...agent.Option) int { return res } - logging.PatchStandardLogger() + if cfg.Instrumentation.Logger.StandardLogger != nil && *cfg.Instrumentation.Logger.StandardLogger { + logging.PatchStandardLogger() + } + if cfg.Instrumentation.Logger.StandardOutput != nil && *cfg.Instrumentation.Logger.StandardOutput { + logging.PatchStdOut() + } + if cfg.Instrumentation.Logger.StandardError != nil && *cfg.Instrumentation.Logger.StandardError { + logging.PatchStdErr() + } scopetesting.Init(m) diff --git a/instrumentation/nethttp/client.go b/instrumentation/nethttp/client.go index 49b49a93..b56d299e 100644 --- a/instrumentation/nethttp/client.go +++ b/instrumentation/nethttp/client.go @@ -14,6 +14,7 @@ import ( "github.com/opentracing/opentracing-go/ext" "github.com/opentracing/opentracing-go/log" + "go.undefinedlabs.com/scopeagent/config" scopeerrors "go.undefinedlabs.com/scopeagent/errors" "go.undefinedlabs.com/scopeagent/instrumentation" ) @@ -49,6 +50,8 @@ type clientOptions struct { spanObserver func(span opentracing.Span, r *http.Request) } +var cfg = config.Get() + // ClientOption controls the behavior of TraceRequest. type ClientOption func(*clientOptions) @@ -158,7 +161,7 @@ func TracerFromRequest(req *http.Request) *Tracer { func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) { // Only trace outgoing requests that are inside an active trace parent := opentracing.SpanFromContext(req.Context()) - if parent == nil { + if parent == nil || (cfg.Instrumentation.Http.Client != nil && !*cfg.Instrumentation.Http.Client) { rt := t.RoundTripper if rt == nil { rt = http.DefaultTransport diff --git a/instrumentation/nethttp/patch.go b/instrumentation/nethttp/patch.go index 8b39fb37..b0d4ceb7 100644 --- a/instrumentation/nethttp/patch.go +++ b/instrumentation/nethttp/patch.go @@ -1,7 +1,6 @@ package nethttp import ( - "go.undefinedlabs.com/scopeagent/env" "net/http" "sync" ) @@ -31,8 +30,8 @@ func PatchHttpDefaultClient(options ...Option) { for _, option := range options { option(transport) } - transport.PayloadInstrumentation = transport.PayloadInstrumentation || env.ScopeInstrumentationHttpPayloads.Value - transport.Stacktrace = transport.Stacktrace || env.ScopeInstrumentationHttpStacktrace.Value + transport.PayloadInstrumentation = transport.PayloadInstrumentation || (cfg.Instrumentation.Http.Payloads != nil && *cfg.Instrumentation.Http.Payloads) + transport.Stacktrace = transport.Stacktrace || (cfg.Instrumentation.Http.Stacktrace != nil && *cfg.Instrumentation.Http.Stacktrace) http.DefaultClient = &http.Client{Transport: transport} }) } diff --git a/instrumentation/nethttp/server.go b/instrumentation/nethttp/server.go index 18b83274..983ffaa9 100644 --- a/instrumentation/nethttp/server.go +++ b/instrumentation/nethttp/server.go @@ -11,7 +11,6 @@ import ( "github.com/opentracing/opentracing-go" "github.com/opentracing/opentracing-go/ext" - "go.undefinedlabs.com/scopeagent/env" "go.undefinedlabs.com/scopeagent/errors" "go.undefinedlabs.com/scopeagent/instrumentation" ) @@ -122,9 +121,9 @@ func middlewareFunc(tr opentracing.Tracer, h http.HandlerFunc, options ...MWOpti for _, opt := range options { opt(&opts) } - opts.payloadInstrumentation = opts.payloadInstrumentation || env.ScopeInstrumentationHttpPayloads.Value + opts.payloadInstrumentation = opts.payloadInstrumentation || (cfg.Instrumentation.Http.Payloads != nil && *cfg.Instrumentation.Http.Payloads) fn := func(w http.ResponseWriter, r *http.Request) { - if !opts.spanFilter(r) { + if !opts.spanFilter(r) || (cfg.Instrumentation.Http.Server != nil && !*cfg.Instrumentation.Http.Server) { h(w, r) return } diff --git a/instrumentation/sql/driver.go b/instrumentation/sql/driver.go index 5b235f22..540670c9 100644 --- a/instrumentation/sql/driver.go +++ b/instrumentation/sql/driver.go @@ -10,7 +10,7 @@ import ( "github.com/opentracing/opentracing-go" - "go.undefinedlabs.com/scopeagent/env" + "go.undefinedlabs.com/scopeagent/config" scopeerrors "go.undefinedlabs.com/scopeagent/errors" "go.undefinedlabs.com/scopeagent/instrumentation" ) @@ -64,8 +64,9 @@ func WrapDriver(d driver.Driver, options ...Option) driver.Driver { for _, option := range options { option(wrapper) } - wrapper.configuration.statementValues = wrapper.configuration.statementValues || env.ScopeInstrumentationDbStatementValues.Value - wrapper.configuration.stacktrace = wrapper.configuration.stacktrace || env.ScopeInstrumentationDbStacktrace.Value + cfg := config.Get() + wrapper.configuration.statementValues = wrapper.configuration.statementValues || (cfg.Instrumentation.DB.StatementValues != nil && *cfg.Instrumentation.DB.StatementValues) + wrapper.configuration.stacktrace = wrapper.configuration.stacktrace || (cfg.Instrumentation.DB.StatementValues != nil && *cfg.Instrumentation.DB.StatementValues) return wrapper } diff --git a/scope.yml b/scope.yml new file mode 100644 index 00000000..712afbfc --- /dev/null +++ b/scope.yml @@ -0,0 +1,40 @@ +#service: 'service-name' #SCOPE_SERVICE +#logger: +# root: '/home/user/projects/scope/log' #SCOPE_LOGGER_ROOT +metadata: #SCOPE_METADATA + sample.key1: $SAMPLE_VAR1 + sample.key2: $PATH + sample.key3: sampleValue3 +#configuration: #SCOPE_CONFIGURATION +# - sample.key1 +# - sample.key2 +# - sample.key3 +instrumentation: + diff_summary: true #SCOPE_INSTRUMENTATION_DIFF_SUMMARY + tests_frameworks: + fail_retries: 4 #SCOPE_INSTRUMENTATION_TESTS_FRAMEWORKS_FAIL_RETRIES + panic_as_fail: true #SCOPE_INSTRUMENTATION_TESTS_FRAMEWORKS_PANIC_AS_FAIL + db: + statement_values: true #SCOPE_INSTRUMENTATION_DB_STATEMENT_VALUES + http: + client: true #SCOPE_INSTRUMENTATION_HTTP_CLIENT + server: true #SCOPE_INSTRUMENTATION_HTTP_SERVER + payloads: true #SCOPE_INSTRUMENTATION_HTTP_PAYLOADS + headers: #SCOPE_INSTRUMENTATION_HTTP_HEADERS + - Authorization + - My-Header-One + - My-Header-Two + logger: + standard_logger: true #SCOPE_INSTRUMENTATION_LOGGER_STANDARD_LOGGER + standard_output: false #SCOPE_INSTRUMENTATION_LOGGER_STANDARD_OUTPUT + standard_error: false #SCOPE_INSTRUMENTATION_LOGGER_STANDARD_ERROR +tracer: + global: true #SCOPE_TRACER_GLOBAL + dispatcher: + healthcheck_frecuency: 60000 #SCOPE_TRACER_DISPATCHER_HEALTHCHECK_FRECUENCY + healthcheck_frecuency_in_testmode: 1000 #SCOPE_TRACER_DISPATCHER_HEALTHCHECK_FRECUENCY_IN_TESTMODE + concurrency_level: 5 #SCOPE_TRACER_DISPATCHER_CONCURRENCY_LEVEL + spans: + max_payload_size: 1000 #SCOPE_TRACER_DISPATCHER_SPANS_MAX_PAYLOAD_SIZE + events: + max_payload_size: 1000 #SCOPE_TRACER_DISPATCHER_EVENTS_MAX_PAYLOAD_SIZE