You've already forked opentelemetry-go
mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2025-10-08 23:21:56 +02:00
This PR adds support for experimental metrics in `otlploggrpc`
- `otel.sdk.exporter.log.inflight`
- `otel.sdk.exporter.log.exported`
- `otel.sdk.exporter.operation.duration`
References:
- #7084
- https://github.com/open-telemetry/opentelemetry-go/issues/7019
- [Follow
guidelines](a5dcd68ebb/CONTRIBUTING.md (encapsulation)
).
-----
```txt
goos: darwin
goarch: arm64
pkg: go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc
cpu: Apple M3
│ disabled.txt │ enabled.txt │
│ sec/op │ sec/op vs base │
ExporterExportLogs/Observability-8 681.5µ ± 3% 684.3µ ± 6% ~ (p=0.315 n=10)
│ disabled.txt │ enabled.txt │
│ B/op │ B/op vs base │
ExporterExportLogs/Observability-8 672.8Ki ± 0% 673.6Ki ± 1% ~ (p=0.247 n=10)
│ disabled.txt │ enabled.txt │
│ allocs/op │ allocs/op vs base │
ExporterExportLogs/Observability-8 9.224k ± 0% 9.232k ± 0% +0.09% (p=0.000 n=10)
```
-----
```txt
goos: darwin
goarch: arm64
pkg: go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc/internal/observ
cpu: Apple M3
│ bench.txt │
│ sec/op │
InstrumentationExportLogs/NoError-8 162.6n ± 3%
InstrumentationExportLogs/PartialError-8 705.5n ± 5%
InstrumentationExportLogs/FullError-8 592.1n ± 1%
geomean 408.0n
│ bench.txt │
│ B/op │
InstrumentationExportLogs/NoError-8 152.0 ± 0%
InstrumentationExportLogs/PartialError-8 697.0 ± 0%
InstrumentationExportLogs/FullError-8 616.0 ± 0%
geomean 402.6
│ bench.txt │
│ allocs/op │
InstrumentationExportLogs/NoError-8 3.000 ± 0%
InstrumentationExportLogs/PartialError-8 10.00 ± 0%
InstrumentationExportLogs/FullError-8 8.000 ± 0%
geomean 6.214
```
-----
```txt
pkg: go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc/internal/observ
cpu: Apple M3
│ parse_target.txt │
│ sec/op │
ParseTarget/HostName-8 38.00n ± ∞ ¹
ParseTarget/HostPort-8 51.33n ± ∞ ¹
ParseTarget/IPv4WithoutPort-8 44.74n ± ∞ ¹
ParseTarget/IPv4WithPort-8 62.56n ± ∞ ¹
ParseTarget/IPv6Bare-8 94.89n ± ∞ ¹
ParseTarget/IPv6Bracket-8 93.78n ± ∞ ¹
ParseTarget/IPv6WithPort-8 57.57n ± ∞ ¹
ParseTarget/UnixSocket-8 8.329n ± ∞ ¹
ParseTarget/UnixAbstractSocket-8 9.082n ± ∞ ¹
ParseTarget/Passthrough-8 58.06n ± ∞ ¹
geomean 40.64n
¹ need >= 6 samples for confidence interval at level 0.95
│ parse_target.txt │
│ B/op │
ParseTarget/HostName-8 48.00 ± ∞ ¹
ParseTarget/HostPort-8 48.00 ± ∞ ¹
ParseTarget/IPv4WithoutPort-8 16.00 ± ∞ ¹
ParseTarget/IPv4WithPort-8 48.00 ± ∞ ¹
ParseTarget/IPv6Bare-8 16.00 ± ∞ ¹
ParseTarget/IPv6Bracket-8 16.00 ± ∞ ¹
ParseTarget/IPv6WithPort-8 48.00 ± ∞ ¹
ParseTarget/UnixSocket-8 0.000 ± ∞ ¹
ParseTarget/UnixAbstractSocket-8 0.000 ± ∞ ¹
ParseTarget/Passthrough-8 48.00 ± ∞ ¹
geomean ²
¹ need >= 6 samples for confidence interval at level 0.95
² summaries must be >0 to compute geomean
│ parse_target.txt │
│ allocs/op │
ParseTarget/HostName-8 1.000 ± ∞ ¹
ParseTarget/HostPort-8 1.000 ± ∞ ¹
ParseTarget/IPv4WithoutPort-8 1.000 ± ∞ ¹
ParseTarget/IPv4WithPort-8 1.000 ± ∞ ¹
ParseTarget/IPv6Bare-8 1.000 ± ∞ ¹
ParseTarget/IPv6Bracket-8 1.000 ± ∞ ¹
ParseTarget/IPv6WithPort-8 1.000 ± ∞ ¹
ParseTarget/UnixSocket-8 0.000 ± ∞ ¹
ParseTarget/UnixAbstractSocket-8 0.000 ± ∞ ¹
ParseTarget/Passthrough-8 1.000 ± ∞ ¹
geomean ²
¹ need >= 6 samples for confidence interval at level 0.95
² summaries must be >0 to compute geomean
```
---------
Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
144 lines
4.0 KiB
Go
144 lines
4.0 KiB
Go
// Code generated by gotmpl. DO NOT MODIFY.
|
|
// source: internal/shared/otlp/observ/target.go.tmpl
|
|
|
|
// Copyright The OpenTelemetry Authors
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package observ // import "go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc/internal/observ"
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"net/netip"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
schemeUnix = "unix"
|
|
schemeUnixAbstract = "unix-abstract"
|
|
)
|
|
|
|
// ParseCanonicalTarget parses a target string and returns the extracted host
|
|
// (domain address or IP), the target port, or an error.
|
|
//
|
|
// If no port is specified, -1 is returned.
|
|
//
|
|
// If no host is specified, an empty string is returned.
|
|
//
|
|
// The target string is expected to always have the form
|
|
// "<scheme>://[authority]/<endpoint>". For example:
|
|
// - "dns:///example.com:42"
|
|
// - "dns://8.8.8.8/example.com:42"
|
|
// - "unix:///path/to/socket"
|
|
// - "unix-abstract:///socket-name"
|
|
// - "passthrough:///192.34.2.1:42"
|
|
//
|
|
// The target is expected to come from the CanonicalTarget method of a gRPC
|
|
// Client.
|
|
func ParseCanonicalTarget(target string) (string, int, error) {
|
|
const sep = "://"
|
|
|
|
// Find scheme. Do not allocate the string by using url.Parse.
|
|
idx := strings.Index(target, sep)
|
|
if idx == -1 {
|
|
return "", -1, fmt.Errorf("invalid target %q: missing scheme", target)
|
|
}
|
|
scheme, endpoint := target[:idx], target[idx+len(sep):]
|
|
|
|
// Check for unix schemes.
|
|
if scheme == schemeUnix || scheme == schemeUnixAbstract {
|
|
return parseUnix(endpoint)
|
|
}
|
|
|
|
// Strip leading slash and any authority.
|
|
if i := strings.Index(endpoint, "/"); i != -1 {
|
|
endpoint = endpoint[i+1:]
|
|
}
|
|
|
|
// DNS, passthrough, and custom resolvers.
|
|
return parseEndpoint(endpoint)
|
|
}
|
|
|
|
// parseUnix parses unix socket targets.
|
|
func parseUnix(endpoint string) (string, int, error) {
|
|
// Format: unix[-abstract]://path
|
|
//
|
|
// We should have "/path" (empty authority) if valid.
|
|
if len(endpoint) >= 1 && endpoint[0] == '/' {
|
|
// Return the full path including leading slash.
|
|
return endpoint, -1, nil
|
|
}
|
|
|
|
// If there's no leading slash, it means there might be an authority
|
|
// Check for authority case (should error): "authority/path"
|
|
if slashIdx := strings.Index(endpoint, "/"); slashIdx > 0 {
|
|
return "", -1, fmt.Errorf("invalid (non-empty) authority: %s", endpoint[:slashIdx])
|
|
}
|
|
|
|
return "", -1, errors.New("invalid unix target format")
|
|
}
|
|
|
|
// parseEndpoint parses an endpoint from a gRPC target.
|
|
//
|
|
// It supports the following formats:
|
|
// - "host"
|
|
// - "host%zone"
|
|
// - "host:port"
|
|
// - "host%zone:port"
|
|
// - "ipv4"
|
|
// - "ipv4%zone"
|
|
// - "ipv4:port"
|
|
// - "ipv4%zone:port"
|
|
// - "ipv6"
|
|
// - "ipv6%zone"
|
|
// - "[ipv6]"
|
|
// - "[ipv6%zone]"
|
|
// - "[ipv6]:port"
|
|
// - "[ipv6%zone]:port"
|
|
//
|
|
// It returns the host or host%zone (domain address or IP), the port (or -1 if
|
|
// not specified), or an error if the input is not a valid.
|
|
func parseEndpoint(endpoint string) (string, int, error) {
|
|
// First check if the endpoint is just an IP address.
|
|
if ip := parseIP(endpoint); ip != "" {
|
|
return ip, -1, nil
|
|
}
|
|
|
|
// If there's no colon, there is no port (IPv6 with no port checked above).
|
|
if !strings.Contains(endpoint, ":") {
|
|
return endpoint, -1, nil
|
|
}
|
|
|
|
host, portStr, err := net.SplitHostPort(endpoint)
|
|
if err != nil {
|
|
return "", -1, fmt.Errorf("invalid host:port %q: %w", endpoint, err)
|
|
}
|
|
|
|
const base, bitSize = 10, 16
|
|
port16, err := strconv.ParseUint(portStr, base, bitSize)
|
|
if err != nil {
|
|
return "", -1, fmt.Errorf("invalid port %q: %w", portStr, err)
|
|
}
|
|
port := int(port16) // port is guaranteed to be in the range [0, 65535].
|
|
|
|
return host, port, nil
|
|
}
|
|
|
|
// parseIP attempts to parse the entire endpoint as an IP address.
|
|
// It returns the normalized string form of the IP if successful,
|
|
// or an empty string if parsing fails.
|
|
func parseIP(ip string) string {
|
|
// Strip leading and trailing brackets for IPv6 addresses.
|
|
if len(ip) >= 2 && ip[0] == '[' && ip[len(ip)-1] == ']' {
|
|
ip = ip[1 : len(ip)-1]
|
|
}
|
|
addr, err := netip.ParseAddr(ip)
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
// Return the normalized string form of the IP.
|
|
return addr.String()
|
|
}
|