diff --git a/README.md b/README.md index abc9ddad..b210978a 100644 --- a/README.md +++ b/README.md @@ -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 @@ -54,9 +59,7 @@ $ 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. @@ -64,6 +67,12 @@ Also there are several [**documents**](./docs) that you may find useful for eith > 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 | @@ -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) \ No newline at end of file +- +- \ No newline at end of file diff --git a/static/alibaba.png b/docs/alibaba.png similarity index 100% rename from static/alibaba.png rename to docs/alibaba.png diff --git a/docs/aliyun.png b/docs/aliyun.png new file mode 100644 index 00000000..929d4ccd Binary files /dev/null and b/docs/aliyun.png differ diff --git a/docs/usage.md b/docs/usage.md new file mode 100644 index 00000000..acb9225c --- /dev/null +++ b/docs/usage.md @@ -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. \ No newline at end of file diff --git a/test/flags_test.go b/test/flags_test.go index 98e967cd..5c363ee6 100644 --- a/test/flags_test.go +++ b/test/flags_test.go @@ -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") @@ -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") +} diff --git a/test/infra.go b/test/infra.go index 9d49ea71..5def004c 100644 --- a/test/infra.go +++ b/test/infra.go @@ -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") diff --git a/tool/config/config.go b/tool/config/config.go index c41a0b3e..7052d6a0 100644 --- a/tool/config/config.go +++ b/tool/config/config.go @@ -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 @@ -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 {