Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ Another interesting feature is the usage of additional packages located under [i
1. [Tracing an application running on Azure Container Apps](docs/azure_container_apps.md)
1. [Tracing Other Go Packages](docs/other_packages.md)
1. [Instrumenting Code Manually](docs/manual_instrumentation.md)
1. [Disabling Spans by Category](docs/disabling_spans.md)
1. [Generic Serverless Agent](/docs/generic_serverless_agent.md)

<!-- Links section -->
Expand Down
3 changes: 2 additions & 1 deletion agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ type agentResponse struct {
} `json:"secrets"`
ExtraHTTPHeaders []string `json:"extraHeaders"`
Tracing struct {
ExtraHTTPHeaders []string `json:"extra-http-headers"`
ExtraHTTPHeaders []string `json:"extra-http-headers"`
Disable []map[string]bool `json:"disable"`
} `json:"tracing"`
}

Expand Down
3 changes: 2 additions & 1 deletion agent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,8 @@ func Test_agentApplyHostSettings(t *testing.T) {
Pid: 37892,
HostID: "myhost",
Tracing: struct {
ExtraHTTPHeaders []string `json:"extra-http-headers"`
ExtraHTTPHeaders []string `json:"extra-http-headers"`
Disable []map[string]bool `json:"disable"`
}{
ExtraHTTPHeaders: []string{"my-unwanted-custom-headers"},
},
Expand Down
43 changes: 43 additions & 0 deletions disable_span.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// (c) Copyright IBM Corp. 2025
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should name the file for the component present, not for a feature.


package instana
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Query: In this implementation, do we need a separate file for spanCategory as such?


type spanCategory string

const (
logging spanCategory = "logging"
unknown spanCategory = "unknown"
)

func (c spanCategory) String() string {
return string(c)
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: A comment would be nice since it is an exported function.

func (opts *TracerOptions) DisableAllCategories() {
opts.Disable = map[string]bool{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Query: Shouldn't this function be defined in the place where TracerOptions is defined?

logging.String(): true,
}
}

// registeredSpanMap maps span types to their categories
var registeredSpanMap map[RegisteredSpanType]spanCategory = map[RegisteredSpanType]spanCategory{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Just check whether a function with(switch cases in the future) will be more suiting here. I think we won't be needing a map in that case.

// logging
LogSpanType: logging,
}

func (r *spanS) getSpanCategory() spanCategory {
// return span category if it is a registered span type
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Query: Shouldn't this function be defined in the place where SpanS is defined?

if c, ok := registeredSpanMap[RegisteredSpanType(r.Operation)]; ok {
return c
}

return unknown
}

func (c spanCategory) Enabled() bool {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Query: Won't Disabled() is more meaningful?

// unrecognized categories are always enabled
if c == unknown {
return true
}
return !sensor.options.Tracer.Disable[c.String()]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe, false while accessing the map can imply either the value is not present or the map is not initialised. Just wanted to make sure that it is as per design. We can discuss.

}
131 changes: 131 additions & 0 deletions disable_span_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// (c) Copyright IBM Corp. 2025
package instana

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestSpanCategoryString(t *testing.T) {
tests := []struct {
name string
category spanCategory
expected string
}{
{
name: "Logging category",
category: logging,
expected: "logging",
},
{
name: "Unknown category",
category: unknown,
expected: "unknown",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := tt.category.String()
if result != tt.expected {
t.Errorf("Expected %s, got %s", tt.expected, result)
}
})
}
}

func TestTracerOptionsDisableAllCategories(t *testing.T) {
opts := &TracerOptions{}
opts.DisableAllCategories()

expectedCategories := []spanCategory{logging}

// Check if all categories are disabled
for _, category := range expectedCategories {
if !opts.Disable[category.String()] {
t.Errorf("Category %s should be disabled", category)
}
}

// Check if the map has the correct size
if len(opts.Disable) != len(expectedCategories) {
t.Errorf("Expected %d disabled categories, got %d", len(expectedCategories), len(opts.Disable))
}
}

func TestGetSpanCategory(t *testing.T) {
tests := []struct {
name string
operation string
expectedCat spanCategory
}{
{
name: "Log span",
operation: string(LogSpanType),
expectedCat: logging,
},
{
name: "Unknown span type",
operation: "unknown-span-type",
expectedCat: unknown,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
span := &spanS{
Operation: tt.operation,
}

result := span.getSpanCategory()

if result != tt.expectedCat {
t.Errorf("Expected category %s, got %s", tt.expectedCat, result)
}
})
}
}

func TestSpanCategoryEnabled(t *testing.T) {
tests := []struct {
name string
category spanCategory
disable map[string]bool
expected bool
}{
{
name: "Category enabled when no categories are disabled",
category: logging,
disable: map[string]bool{},
expected: true,
},
{
name: "Category disabled when specifically disabled",
category: logging,
disable: map[string]bool{"logging": true},
expected: false,
},
{
name: "Unknown category always enabled",
category: unknown,
disable: map[string]bool{"logging": true},
expected: true,
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
InitCollector(&Options{
Tracer: TracerOptions{
Disable: tc.disable,
},
})
defer ShutdownCollector()

result := tc.category.Enabled()

assert.Equal(t, tc.expected, result)
})
}
}
87 changes: 87 additions & 0 deletions docs/disabling_spans.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Disabling Log Spans

The Instana Go Tracer allows you to disable log spans to reduce the amount of data being collected and processed. This can be useful in high-volume environments or when you want to focus on specific types of traces.

## Supported Span Categories

Currently, only the following span category can be disabled:

| Category | Description | Affected Instrumentations |
| --------- | ----------- | ------------------------- |
| `logging` | Log spans | `logrus` |

## Configuration Methods

There are three ways to disable log spans:

### 1. Using Code

You can disable log spans when initializing the tracer:

```go
col := instana.InitCollector(&instana.Options{
Service: "My Service",
Tracer: instana.TracerOptions{
Disable: map[string]bool{
"logging": true, // Disable log spans
},
},
})
```

### 2. Using Environment Variables

You can disable log spans using the `INSTANA_TRACING_DISABLE` environment variable:

```bash
# Disable log spans
export INSTANA_TRACING_DISABLE="logging"

# Disable all tracing
export INSTANA_TRACING_DISABLE=true
```

### 3. Using Configuration File

You can create a YAML configuration file and specify its path using the `INSTANA_CONFIG_PATH` environment variable:

```yaml
# config.yaml
tracing:
disable:
- logging
```

```bash
export INSTANA_CONFIG_PATH=/path/to/config.yaml
```

## Priority Order

When multiple configuration methods are used, they are applied in the following order of precedence:

1. Configuration file (`INSTANA_CONFIG_PATH`)
2. Environment variable (`INSTANA_TRACING_DISABLE`)
3. Code-level configuration

## Example

### Disable Log Spans

```go
col := instana.InitCollector(&instana.Options{
Service: "My Service",
Tracer: instana.TracerOptions{
Disable: map[string]bool{
"logging": true,
},
},
})
```

## Use Cases

- **Performance Optimization**: In high-throughput applications, disabling log spans can reduce the overhead of tracing.
- **Cost Management**: Reduce the volume of trace data sent to Instana to manage costs.
- **Focus on Specific Areas**: Disable log spans to focus on the parts of your application that need attention.
- **Testing**: Temporarily disable log spans during testing or development.
9 changes: 8 additions & 1 deletion docs/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,13 @@ IncludeProfilerFrames is whether to include profiler calls into the profile or n

**Type:** [TracerOptions](https://pkg.go.dev/github.com/instana/go-sensor#TracerOptions)

Tracer contains tracer-specific configuration used by all tracers
Tracer contains tracer-specific configuration used by all tracers. Key options include:

- **Disable**: A map of span categories to disable. Currently, only the "logging" category is supported. See [Disabling Log Spans](disabling_spans.md) for details.
- **DropAllLogs**: Turns log events on all spans into no-ops when set to true.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Query: How can the user set this, DropAllLogs? Is it a redundant one? May be we can discuss.

- **MaxLogsPerSpan**: Maximum number of log records that can be attached to a span.
- **Secrets**: A secrets matcher used to filter out sensitive data from HTTP requests, database connection strings, etc.
- **CollectableHTTPHeaders**: A list of HTTP headers to be collected from requests.

#### AgentClient

Expand Down Expand Up @@ -97,3 +103,4 @@ Go Tracer only captures log spans with severity `warn` or higher.
[Tracing SQL Driver Databases](sql.md) |
[Tracing Other Go Packages](other_packages.md) |
[Instrumenting Code Manually](manual_instrumentation.md)

Loading
Loading