Skip to content

Commit

Permalink
feat: set config by env variables (alibaba#236)
Browse files Browse the repository at this point in the history
* feat: set config by env variables

* update usage doc
  • Loading branch information
y1yang0 authored Dec 3, 2024
1 parent 694ec4c commit f2db3ac
Show file tree
Hide file tree
Showing 7 changed files with 177 additions and 5 deletions.
18 changes: 14 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ $ make install # build and install

# Getting Started

Check the version by running:
```bash
$ otel version
```

The configuration for the tool can be set by the following command:

```bash
Expand All @@ -54,16 +59,20 @@ $ otel go build -o app cmd/app
$ otel go build -gcflags="-m" cmd/app
```

You can also explore [**these examples**](./example/) to get hands-on experience.

Also there are several [**documents**](./docs) that you may find useful for either understanding the project or contributing to it.
The detailed usage of otel tool can be found in [**Usage**](./docs/usage.md).

> [!NOTE]
> If you find any compilation failures while `go build` works, it's likely a bug.
> Please feel free to file a bug
> at [GitHub Issues](https://github.com/alibaba/opentelemetry-go-auto-instrumentation/issues)
> to help us enhance this project.
# Examples

You can also explore [**these examples**](./example/) to get hands-on experience. They are designed to construct a full picture of how to use the tool in different scenarios.

Also there are several [**documents**](./docs) that you may find useful for either understanding the project or contributing to it.

# Supported Libraries

| Plugin Name | Repository Url | Min Supported Version | Max Supported Version |
Expand Down Expand Up @@ -108,4 +117,5 @@ to engage with us.

These are only part of the companies using this project, for reference only. If you are using this project, please [add your company here](https://github.com/alibaba/opentelemetry-go-auto-instrumentation/issues/225) to tell us your scenario to make this project better.

![Alibaba Group](./static/alibaba.png)
- <img src="./docs/alibaba.png" width="80">
- <img src="./docs/aliyun.png" width="100">
File renamed without changes
Binary file added docs/aliyun.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
75 changes: 75 additions & 0 deletions docs/usage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# `Otel` Usage Guide

## Introduction
This guide provides a detailed overview of configuring and using the otel tool effectively. This tool allows you to set various configuration options, build your projects, and customize your workflow for optimal performance.

## Configuration
The primary method of configuring the tool is through the `otel set` command. This command allows you to specify various settings tailored to your needs:

Verbose Logging: Enable verbose logging to receive detailed output from the tool, which is helpful for troubleshooting and understanding the tool's processes.
```bash
$ otel set -verbose
```

Debug Mode: Turn on debug mode to gather debug-level insights and information.
```bash
$ otel set -debug
```

Multiple Configurations: Set multiple configurations at once. For instance, enable both debug and verbose modes while using a custom rule file:
```bash
$ otel set -debug -verbose -rule=custom.json
```

Custom Rules Only: Disable the default rule set and apply only specific custom rules. This is particularly useful when you need a tailored rule set for your project.
```bash
$ otel set -disabledefault -rule=custom.json
```

Combination of Default and Custom Rules: Use both the default rules and custom rules to provide a comprehensive configuration:
```bash
$ otel set -rule=custom.json
```

Multiple Rule Files: Combine multiple custom rule files along with the default rules, which can be specified as a comma-separated list:
```bash
$ otel set -rule=a.json,b.json
```

## Using Environment Variables
In addition to using the `otel set` command, configuration can also be overridden using environment variables. For example, the `OTELTOOL_DEBUG` environment variable allows you to force the tool into debug mode temporarily, making this approach effective for one-time configurations without altering permanent settings.

```bash
$ export OTELTOOL_DEBUG=true
$ export OTELTOOL_VERBOSE=true
```

The names of the environment variables correspond to the configuration options available in the `otel set` command with the `OTELTOOL_` prefix.

Full List of Environment Variables:

- `OTELTOOL_DEBUG`: Enable debug mode.
- `OTELTOOL_VERBOSE`: Enable verbose logging.
- `OTELTOOL_RULE_JSON_FILES`: Specify custom rule files.
- `OTELTOOL_DISABLE_DEFAULT`: Disable default rules.

This approach provides flexibility for testing changes and experimenting with configurations without permanently altering your existing setup.

## Building Projects
Once configurations are in place, you can build your project with prefixed `otel` commands. This integrates the tool's configuration directly into the build process:

Standard Build: Build your project with default settings.
```bash
$ otel go build
```

Output to Specific Location: Build your project and specify an output location.
```bash
$ otel go build -o app cmd/app
```

Passing Compiler Flags: Use compiler flags for more customized builds.
```bash
$ otel go build -gcflags="-m" cmd/app
```
No matter how complex your project is, the otel tool simplifies the process by automatically instrumenting your code for effective observability, the only requirement being the addition of the `otel` prefix to your build commands.
17 changes: 16 additions & 1 deletion test/flags_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ import (
"github.com/alibaba/opentelemetry-go-auto-instrumentation/tool/shared"
)

const AppName = "flags"

func TestFlags(t *testing.T) {
const AppName = "flags"
UseApp(AppName)

RunGoBuildFallible(t, "go", "build", "-thisisnotvalid")
Expand All @@ -42,3 +43,17 @@ func TestFlags(t *testing.T) {
RunGoBuild(t)
RunGoBuild(t, "")
}

func TestFlagConfigOverwriteNo(t *testing.T) {
UseApp(AppName)

RunSet(t, "-verbose=false")
RunGoBuildWithEnv(t, []string{"OTELTOOL_VERBOSE=true"},
"go", "build")
ExpectPreprocessContains(t, shared.DebugLogFile, "Available")

RunSet(t, "-verbose=true")
RunGoBuildWithEnv(t, []string{"OTELTOOL_VERBOSE=false"},
"go", "build")
ExpectPreprocessNotContains(t, shared.DebugLogFile, "Available")
}
22 changes: 22 additions & 0 deletions test/infra.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,28 @@ func RunGoBuild(t *testing.T, args ...string) {
}
}

func RunGoBuildWithEnv(t *testing.T, envs []string, args ...string) {
util.Assert(pwd != "", "pwd is empty")
RunSet(t, "-debuglog")
path := filepath.Join(filepath.Dir(pwd), getExecName())
cmd := runCmd(append([]string{path}, args...))
cmd.Env = append(cmd.Env, envs...)
err := cmd.Run()
if err != nil {
stderr := readStderrLog(t)
stdout := readStdoutLog(t)
t.Log(stdout)
t.Log("\n\n\n")
t.Log(stderr)
log1 := ReadPreprocessLog(t, shared.DebugLogFile)
log2 := ReadInstrumentLog(t, shared.DebugLogFile)
text := fmt.Sprintf("failed to run instrument: %v\n", err)
text += fmt.Sprintf("preprocess: %v\n", log1)
text += fmt.Sprintf("instrument: %v\n", log2)
t.Fatal(text)
}
}

func RunGoBuildFallible(t *testing.T, args ...string) {
util.Assert(pwd != "", "pwd is empty")
RunSet(t, "-debuglog")
Expand Down
50 changes: 50 additions & 0 deletions tool/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,18 @@ import (
"log"
"os"
"path/filepath"
"reflect"
"strings"
"unicode"

"github.com/alibaba/opentelemetry-go-auto-instrumentation/tool/shared"
"github.com/alibaba/opentelemetry-go-auto-instrumentation/tool/util"
)

const (
EnvPrefix = "OTELTOOL_"
)

type BuildConfig struct {
// RuleJsonFiles is the name of the rule file. It is used to tell instrument
// tool where to find the instrument rules. Multiple rules are separated by
Expand Down Expand Up @@ -162,12 +168,56 @@ func loadConfig() (*BuildConfig, error) {
return bc, nil
}

func toUpperSnakeCase(input string) string {
var result []rune

for i, char := range input {
if unicode.IsUpper(char) {
if i != 0 {
result = append(result, '_')
}
result = append(result, unicode.ToUpper(char))
} else {
result = append(result, unicode.ToUpper(char))
}
}

return string(result)
}
func loadConfigFromEnv(conf *BuildConfig) {
// Environment variables are able to overwrite the config items even if the
// config file sets them. The environment variable name is the upper snake
// case of the config item name, prefixed with "OTELTOOL_". For example, the
// environment variable for "DebugLog" is "OTELTOOL_DEBUG_LOG".
typ := reflect.TypeOf(*conf)
for i := 0; i < typ.NumField(); i++ {
field := typ.Field(i)
envKey := fmt.Sprintf("%s%s", EnvPrefix, toUpperSnakeCase(field.Name))
envVal := os.Getenv(envKey)
if envVal != "" {
log.Printf("Overwrite config %s with environment variable %s",
field.Name, envKey)
v := reflect.ValueOf(conf).Elem()
f := v.FieldByName(field.Name)
switch f.Kind() {
case reflect.Bool:
f.SetBool(envVal == "true")
case reflect.String:
f.SetString(envVal)
default:
log.Fatalf("Unsupported config type %s", f.Kind())
}
}
}
}

func InitConfig() (err error) {
// Load build config from json file
conf, err = loadConfig()
if err != nil {
return fmt.Errorf("failed to load build config: %w", err)
}
loadConfigFromEnv(conf)

err = conf.parseRuleFiles()
if err != nil {
Expand Down

0 comments on commit f2db3ac

Please sign in to comment.