Skip to content

Commit 36ca990

Browse files
authored
Add http/protobuf support for Coralogix exporter (open-telemetry#43219)
<!--Ex. Fixing a bug - Describe the bug and how this fixes the issue. Ex. Adding a feature - Explain what this achieves.--> #### Description <!-- Issue number (e.g. #1234) or full URL to issue, if applicable. --> #### Link to tracking issue Fixes open-telemetry#43216 <!--Describe what testing was performed and which tests were added.--> #### Testing Tested with: ```yaml receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 exporters: debug: coralogix: protocol: http application_name: otel application_name_attributes: - service.name - k8s.namespace.name - service.namespace domain: eu2.coralogix.com subsystem_name: k8s-saas subsystem_name_attributes: - subsystem.name private_key: ${env:CORALOGIX_PRIVATE_KEY} service: pipelines: traces: receivers: [otlp] exporters: [coralogix, debug] metrics: receivers: [otlp] exporters: [coralogix, debug] logs: receivers: [otlp] exporters: [coralogix, debug] ``` And ```yaml receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 exporters: debug: coralogix: application_name: otel application_name_attributes: - service.name - k8s.namespace.name - service.namespace domain: eu2.coralogix.com subsystem_name: k8s-saas subsystem_name_attributes: - subsystem.name private_key: ${env:CORALOGIX_PRIVATE_KEY} service: pipelines: traces: receivers: [otlp] exporters: [coralogix, debug] metrics: receivers: [otlp] exporters: [coralogix, debug] logs: receivers: [otlp] exporters: [coralogix, debug] ``` Also did some tests with proxy. <!--Describe the documentation added.--> #### Documentation - Changes done in `README.md`. Signed-off-by: Israel Blancas <[email protected]>
1 parent 63e2263 commit 36ca990

21 files changed

+1803
-281
lines changed

.chloggen/43216.yaml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: 'enhancement'
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
7+
component: exporter/coralogix
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Add HTTP/protobuf protocol support alongside existing gRPC transport.
11+
12+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
13+
issues: [43216]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext: |
19+
The exporter now supports both gRPC (default) and HTTP/protobuf protocols for sending telemetry data.
20+
HTTP transport enables proxy support and provides an alternative for environments where gRPC is restricted.
21+
Configure using the `protocol` field with values "grpc" or "http".
22+
23+
# If your change doesn't affect end users or the exported elements of any package,
24+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
25+
# Optional: The change log or logs in which this entry should be included.
26+
# e.g. '[user]' or '[user, api]'
27+
# Include 'user' if the change is relevant to end users.
28+
# Include 'api' if there is a change to a library API.
29+
# Default: '[user]'
30+
change_logs: []

exporter/coralogixexporter/README.md

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ exporters:
3434
# Your Coralogix private key is sensitive
3535
private_key: "xxx"
3636

37+
# (Optional) Protocol to use for communication: "grpc" (default) or "http"
38+
protocol: "grpc"
39+
3740
# (Optional) Ordered list of Resource attributes that are used for Coralogix
3841
# AppName and SubSystem values. The first non-empty Resource attribute is used.
3942
# Example: application_name_attributes: ["k8s.namespace.name", "service.namespace"]
@@ -43,7 +46,7 @@ exporters:
4346
subsystem_name_attributes:
4447
- "service.name"
4548

46-
# Traces, Metrics and Logs emitted by this OpenTelemetry exporter
49+
# Traces, Metrics and Logs emitted by this OpenTelemetry exporter
4750
# are tagged in Coralogix with the default application and subsystem constants.
4851
application_name: "MyBusinessEnvironment"
4952
subsystem_name: "MyBusinessSystem"
@@ -52,13 +55,50 @@ exporters:
5255
sending_queue:
5356
sizer: bytes
5457
batch:
55-
min_size: 4194304
58+
min_size: 4194304
5659
max_size: 8388608
5760

5861
# (Optional) Timeout is the timeout for every attempt to send data to the backend.
5962
timeout: 30s
6063
```
6164
65+
### Transport Protocol
66+
67+
The Coralogix exporter supports two transport protocols:
68+
- **gRPC** (default): Uses gRPC for efficient binary communication
69+
- **HTTP**: Uses HTTP with protobuf encoding, useful for proxy support or environments where gRPC is restricted
70+
71+
To use HTTP protocol:
72+
```yaml
73+
exporters:
74+
coralogix:
75+
protocol: "http"
76+
domain: "coralogix.com"
77+
```
78+
79+
#### Using HTTP Protocol with Proxy
80+
81+
When using HTTP protocol, you can configure proxy settings:
82+
83+
```yaml
84+
exporters:
85+
coralogix:
86+
protocol: "http"
87+
domain: "coralogix.com"
88+
private_key: "xxx"
89+
application_name: "MyApp"
90+
subsystem_name: "MySubsystem"
91+
domain_settings:
92+
proxy_url: "http://proxy.example.com:8080"
93+
timeout: 30s
94+
```
95+
96+
**Notes**:
97+
- Proxy support (`proxy_url`) is only available when using the HTTP protocol. gRPC protocol does not support this setting.
98+
- Signal-specific settings (logs, traces, metrics) take precedence over `domain_settings`.
99+
- **The profiles signal is not supported when using HTTP protocol**. Use gRPC protocol (default) if you need to send profiles data.
100+
```
101+
62102
### Compression
63103

64104
By default, the Coralogix exporter uses gzip compression. Alternatively, you can use zstd compression, for example:
@@ -70,7 +110,7 @@ exporters:
70110
compression: "zstd"
71111
```
72112
73-
### v0.76.0 Coralogix Domain
113+
### v0.76.0 Coralogix Domain
74114
75115
Since v0.76.0 you can specify Coralogix domain in the configuration file instead of specifying different endpoints for traces, metrics and logs. For example, the configuration below, can be replaced with domain field:
76116

exporter/coralogixexporter/config.go

Lines changed: 116 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,16 @@
44
package coralogixexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/coralogixexporter"
55

66
import (
7+
"context"
78
"errors"
89
"fmt"
10+
"net/http"
911
"strings"
1012
"time"
1113

14+
"go.opentelemetry.io/collector/component"
1215
"go.opentelemetry.io/collector/config/configgrpc"
16+
"go.opentelemetry.io/collector/config/confighttp"
1317
"go.opentelemetry.io/collector/config/configopaque"
1418
"go.opentelemetry.io/collector/config/configretry"
1519
"go.opentelemetry.io/collector/exporter/exporterhelper"
@@ -19,33 +23,67 @@ import (
1923
const (
2024
cxAppNameAttrName = "cx.application.name"
2125
cxSubsystemNameAttrName = "cx.subsystem.name"
26+
httpProtocol = "http"
27+
grpcProtocol = "grpc"
2228
)
2329

24-
// Config defines by Coralogix.
30+
// TransportConfig extends configgrpc.ClientConfig with additional HTTP-specific settings
31+
type TransportConfig struct {
32+
// Embed the gRPC configuration to ensure backward compatibility
33+
configgrpc.ClientConfig `mapstructure:",squash"`
34+
35+
// The following fields are only used when protocol is "http"
36+
ProxyURL string `mapstructure:"proxy_url,omitempty"` // Used only if protocol is http
37+
Timeout time.Duration `mapstructure:"timeout,omitempty"` // Used only if protocol is http
38+
}
39+
40+
func (c *TransportConfig) ToHTTPClient(ctx context.Context, host component.Host, settings component.TelemetrySettings) (*http.Client, error) {
41+
headers := c.Headers
42+
if headers == nil {
43+
headers = make(map[string]configopaque.String)
44+
}
45+
headers["Content-Type"] = "application/x-protobuf"
46+
47+
httpClientConfig := confighttp.ClientConfig{
48+
ProxyURL: c.ProxyURL,
49+
TLS: c.TLS,
50+
ReadBufferSize: c.ReadBufferSize,
51+
WriteBufferSize: c.WriteBufferSize,
52+
Timeout: c.Timeout,
53+
Headers: headers,
54+
Compression: c.Compression,
55+
}
56+
return httpClientConfig.ToClient(ctx, host, settings)
57+
}
58+
59+
// Config defines configuration for Coralogix exporter.
2560
type Config struct {
2661
QueueSettings exporterhelper.QueueBatchConfig `mapstructure:"sending_queue"`
2762
configretry.BackOffConfig `mapstructure:"retry_on_failure"`
2863
TimeoutSettings exporterhelper.TimeoutConfig `mapstructure:",squash"`
2964

65+
// Protocol to use for communication. Options: "grpc" (default), "http"
66+
Protocol string `mapstructure:"protocol"`
67+
3068
// Coralogix domain
3169
Domain string `mapstructure:"domain"`
3270

33-
// GRPC Settings used with Domain
34-
DomainSettings configgrpc.ClientConfig `mapstructure:"domain_settings"`
71+
// Transport settings used with Domain (supports both gRPC and HTTP)
72+
DomainSettings TransportConfig `mapstructure:"domain_settings"`
3573

3674
// Use AWS PrivateLink for the domain
3775
PrivateLink bool `mapstructure:"private_link"`
3876

39-
// Coralogix traces ingress endpoint
40-
Traces configgrpc.ClientConfig `mapstructure:"traces"`
77+
// Coralogix traces ingress endpoint (supports both gRPC and HTTP)
78+
Traces TransportConfig `mapstructure:"traces"`
4179

42-
// The Coralogix metrics ingress endpoint
43-
Metrics configgrpc.ClientConfig `mapstructure:"metrics"`
80+
// The Coralogix metrics ingress endpoint (supports both gRPC and HTTP)
81+
Metrics TransportConfig `mapstructure:"metrics"`
4482

45-
// The Coralogix logs ingress endpoint
46-
Logs configgrpc.ClientConfig `mapstructure:"logs"`
83+
// The Coralogix logs ingress endpoint (supports both gRPC and HTTP)
84+
Logs TransportConfig `mapstructure:"logs"`
4785

48-
// The Coralogix profiles ingress endpoint
86+
// The Coralogix profiles ingress endpoint (gRPC only)
4987
Profiles configgrpc.ClientConfig `mapstructure:"profiles"`
5088

5189
// Your Coralogix private key (sensitive) for authentication
@@ -78,6 +116,10 @@ func isEmpty(endpoint string) bool {
78116
}
79117

80118
func (c *Config) Validate() error {
119+
if c.Protocol != grpcProtocol && c.Protocol != httpProtocol && c.Protocol != "" {
120+
return fmt.Errorf("protocol must be %s or %s", grpcProtocol, httpProtocol)
121+
}
122+
81123
// validate that at least one endpoint is set up correctly
82124
if isEmpty(c.Domain) &&
83125
isEmpty(c.Traces.Endpoint) &&
@@ -101,6 +143,12 @@ func (c *Config) Validate() error {
101143
return errors.New("`rate_limiter.duration` must be greater than 0")
102144
}
103145
}
146+
147+
// Validate that HTTP protocol is not used with profiles
148+
if c.Protocol == httpProtocol && !isEmpty(c.Profiles.Endpoint) {
149+
return errors.New("profiles signal is not supported with HTTP protocol, use gRPC protocol (default) instead")
150+
}
151+
104152
return nil
105153
}
106154

@@ -146,7 +194,7 @@ func (c *Config) getMetadataFromResource(res pcommon.Resource) (appName, subsyst
146194
}
147195

148196
func (c *Config) getDomainGrpcSettings() *configgrpc.ClientConfig {
149-
settings := c.DomainSettings
197+
settings := c.DomainSettings.ClientConfig
150198
domain := c.Domain
151199

152200
// If PrivateLink is enabled, use the private link endpoint.
@@ -159,3 +207,60 @@ func (c *Config) getDomainGrpcSettings() *configgrpc.ClientConfig {
159207

160208
return &settings
161209
}
210+
211+
// getMergedTransportConfig returns a TransportConfig that merges signal-specific settings with domain settings.
212+
// Signal-specific settings take precedence over domain settings.
213+
func (c *Config) getMergedTransportConfig(signalConfig *TransportConfig) *TransportConfig {
214+
merged := c.DomainSettings
215+
216+
if signalConfig.ProxyURL != "" {
217+
merged.ProxyURL = signalConfig.ProxyURL
218+
}
219+
if signalConfig.Timeout != 0 {
220+
merged.Timeout = signalConfig.Timeout
221+
}
222+
223+
if signalConfig.Compression != "" {
224+
merged.Compression = signalConfig.Compression
225+
}
226+
if signalConfig.TLS.Insecure || signalConfig.TLS.InsecureSkipVerify || signalConfig.TLS.CAFile != "" {
227+
merged.TLS = signalConfig.TLS
228+
}
229+
if len(signalConfig.Headers) > 0 {
230+
// Deep-copy domain headers to avoid mutating the shared map
231+
headers := make(map[string]configopaque.String)
232+
for k, v := range merged.Headers {
233+
headers[k] = v
234+
}
235+
for k, v := range signalConfig.Headers {
236+
headers[k] = v
237+
}
238+
merged.Headers = headers
239+
}
240+
if signalConfig.WriteBufferSize > 0 {
241+
merged.WriteBufferSize = signalConfig.WriteBufferSize
242+
}
243+
if signalConfig.ReadBufferSize > 0 {
244+
merged.ReadBufferSize = signalConfig.ReadBufferSize
245+
}
246+
if signalConfig.WaitForReady {
247+
merged.WaitForReady = signalConfig.WaitForReady
248+
}
249+
if signalConfig.BalancerName != "" {
250+
merged.BalancerName = signalConfig.BalancerName
251+
}
252+
if signalConfig.Keepalive.HasValue() {
253+
merged.Keepalive = signalConfig.Keepalive
254+
}
255+
if signalConfig.Auth.HasValue() {
256+
merged.Auth = signalConfig.Auth
257+
}
258+
259+
if isEmpty(signalConfig.Endpoint) {
260+
merged.Endpoint = c.getDomainGrpcSettings().Endpoint
261+
} else {
262+
merged.Endpoint = signalConfig.Endpoint
263+
}
264+
265+
return &merged
266+
}

0 commit comments

Comments
 (0)