Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add Classic Ingest Key support #245

Merged
merged 3 commits into from
Mar 4, 2024
Merged
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
23 changes: 17 additions & 6 deletions otlp/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ const (
const fieldSizeMax = math.MaxUint16

var (
legacyApiKeyPattern = regexp.MustCompile("^[0-9a-f]{32}$")
classicApiKeyPattern = regexp.MustCompile("^[0-9a-f]*$")
classicIngestKeyPattern = regexp.MustCompile("^hc[a-z]ic_[0-9a-z]*$")
// Incoming OpenTelemetry HTTP Content-Types (e.g. "application/protobuf") we support
supportedContentTypes = []string{
"application/protobuf",
Expand Down Expand Up @@ -87,6 +88,16 @@ func IsContentTypeSupported(contentType string) bool {
return false
}

// IsClassicApiKey checks if the given API key is a Classic API key.
func IsClassicApiKey(key string) bool {
if len(key) == 32 {
Copy link
Contributor Author

@jharley jharley Mar 1, 2024

Choose a reason for hiding this comment

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

I removed the "len 0" check here as that wasn't being considered previously

return classicApiKeyPattern.MatchString(key)
} else if len(key) == 64 {
return classicIngestKeyPattern.MatchString(key)
}
return false
}

// List of HTTP Content Encodings supported for OTLP ingest.
func GetSupportedContentEncodings() []string {
return supportedContentEncodings
Expand Down Expand Up @@ -126,8 +137,8 @@ type RequestInfo struct {
GRPCAcceptEncoding string
}

func (ri RequestInfo) hasLegacyKey() bool {
return legacyApiKeyPattern.MatchString(ri.ApiKey)
func (ri RequestInfo) hasClassicKey() bool {
return IsClassicApiKey(ri.ApiKey)
}

// ValidateTracesHeaders validates required headers/metadata for a trace OTLP request
Expand All @@ -138,7 +149,7 @@ func (ri *RequestInfo) ValidateTracesHeaders() error {
if len(ri.ApiKey) == 0 {
return ErrMissingAPIKeyHeader
}
if ri.hasLegacyKey() && len(ri.Dataset) == 0 {
if ri.hasClassicKey() && len(ri.Dataset) == 0 {
return ErrMissingDatasetHeader
}
return nil // no error, headers passed all the validations
Expand All @@ -152,7 +163,7 @@ func (ri *RequestInfo) ValidateMetricsHeaders() error {
if len(ri.ApiKey) == 0 {
return ErrMissingAPIKeyHeader
}
if ri.hasLegacyKey() && len(ri.Dataset) == 0 {
if ri.hasClassicKey() && len(ri.Dataset) == 0 {
return ErrMissingDatasetHeader
}
return nil // no error, headers passed all the validations
Expand Down Expand Up @@ -312,7 +323,7 @@ func isInstrumentationLibrary(libraryName string) bool {

func getDataset(ri RequestInfo, attrs map[string]interface{}) string {
var dataset string
if ri.hasLegacyKey() {
if ri.hasClassicKey() {
dataset = ri.Dataset
} else {
serviceName, ok := attrs["service.name"].(string)
Expand Down
12 changes: 12 additions & 0 deletions otlp/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,13 @@ func TestValidateTracesHeaders(t *testing.T) {
{name: "no key, no dataset", apikey: "", dataset: "", contentType: "application/protobuf", err: ErrMissingAPIKeyHeader},
{name: "no key, dataset present", apikey: "", dataset: "dataset", contentType: "application/protobuf", err: ErrMissingAPIKeyHeader},
{name: "classic/no dataset", apikey: "a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1", dataset: "", contentType: "application/protobuf", err: ErrMissingDatasetHeader},
{name: "classic ingest key/no dataset", apikey: "hcxic_1234567890123456789012345678901234567890123456789012345678", dataset: "", contentType: "application/protobuf", err: ErrMissingDatasetHeader},
{name: "classic/dataset present", apikey: "a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1", dataset: "dataset", contentType: "application/protobuf", err: nil},
{name: "classic ingest key/dataset present", apikey: "hcxic_1234567890123456789012345678901234567890123456789012345678", dataset: "dataset", contentType: "application/protobuf", err: nil},
{name: "E&S/no dataset", apikey: "abc123DEF456ghi789jklm", dataset: "", contentType: "application/protobuf", err: nil},
{name: "E&S ingest key/no dataset", apikey: "hcxik_1234567890123456789012345678901234567890123456789012345678", dataset: "", contentType: "application/protobuf", err: nil},
{name: "E&S/dataset present", apikey: "abc123DEF456ghi789jklm", dataset: "dataset", contentType: "application/protobuf", err: nil},
{name: "E&S ingest key/dataset present", apikey: "hcxik_1234567890123456789012345678901234567890123456789012345678", dataset: "dataset", contentType: "application/protobuf", err: nil},
{name: "content-type/(missing)", apikey: "apikey", dataset: "dataset", contentType: "", err: ErrInvalidContentType},
{name: "content-type/javascript", apikey: "apikey", dataset: "dataset", contentType: "application/javascript", err: ErrInvalidContentType},
{name: "content-type/xml", apikey: "apikey", dataset: "dataset", contentType: "application/xml", err: ErrInvalidContentType},
Expand Down Expand Up @@ -161,10 +165,14 @@ func TestValidateMetricsHeaders(t *testing.T) {
{name: "no key, dataset present", apikey: "", dataset: "dataset", contentType: "application/protobuf", err: ErrMissingAPIKeyHeader},
// classic environments need to tell us which dataset to put metrics in
{name: "classic/no dataset", apikey: "a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1", dataset: "", contentType: "application/protobuf", err: ErrMissingDatasetHeader},
{name: "classic ingest key/no dataset", apikey: "hcxic_1234567890123456789012345678901234567890123456789012345678", dataset: "", contentType: "application/protobuf", err: ErrMissingDatasetHeader},
{name: "classic/dataset present", apikey: "a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1", dataset: "dataset", contentType: "application/protobuf", err: nil},
{name: "classic ingest key/dataset present", apikey: "hcxic_1234567890123456789012345678901234567890123456789012345678", dataset: "dataset", contentType: "application/protobuf", err: nil},
// dataset header not required for E&S, there's a fallback
{name: "E&S/no dataset", apikey: "abc123DEF456ghi789jklm", dataset: "", contentType: "application/protobuf", err: nil},
{name: "E&S ingest key/no dataset", apikey: "hcxik_1234567890123456789012345678901234567890123456789012345678", dataset: "", contentType: "application/protobuf", err: nil},
{name: "E&S/dataset present", apikey: "abc123DEF456ghi789jklm", dataset: "dataset", contentType: "application/protobuf", err: nil},
{name: "E&S ingest key/dataset present", apikey: "hcxik_1234567890123456789012345678901234567890123456789012345678", dataset: "dataset", contentType: "application/protobuf", err: nil},
{name: "content-type/(missing)", apikey: "apikey", dataset: "dataset", contentType: "", err: ErrInvalidContentType},
{name: "content-type/javascript", apikey: "apikey", dataset: "dataset", contentType: "application/javascript", err: ErrInvalidContentType},
{name: "content-type/xml", apikey: "apikey", dataset: "dataset", contentType: "application/xml", err: ErrInvalidContentType},
Expand Down Expand Up @@ -201,9 +209,13 @@ func TestValidateLogsHeaders(t *testing.T) {
// logs will use dataset header if present, but log ingest will also use service.name in the data
// and we will have a sensible default if neither are present, so a missing dataset header is not an error here
{name: "classic/no dataset", apikey: "a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1", dataset: "", contentType: "application/protobuf", err: nil},
{name: "classic ingest key/no dataset", apikey: "hcxic_1234567890123456789012345678901234567890123456789012345678", dataset: "", contentType: "application/protobuf", err: nil},
{name: "classic/dataset present", apikey: "a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1", dataset: "dataset", contentType: "application/protobuf", err: nil},
{name: "classic ingest key/dataset present", apikey: "hcxic_1234567890123456789012345678901234567890123456789012345678", dataset: "dataset", contentType: "application/protobuf", err: nil},
{name: "E&S/no dataset", apikey: "abc123DEF456ghi789jklm", dataset: "", contentType: "application/protobuf", err: nil},
{name: "E&S ingest key/no dataset", apikey: "hcxik_1234567890123456789012345678901234567890123456789012345678", dataset: "", contentType: "application/protobuf", err: nil},
{name: "E&S/dataset present", apikey: "abc123DEF456ghi789jklm", dataset: "dataset", contentType: "application/protobuf", err: nil},
{name: "E&S ingest key/dataset present", apikey: "hcxik_1234567890123456789012345678901234567890123456789012345678", dataset: "dataset", contentType: "application/protobuf", err: nil},
{name: "content-type/(missing)", apikey: "apikey", dataset: "dataset", contentType: "", err: ErrInvalidContentType},
{name: "content-type/javascript", apikey: "apikey", dataset: "dataset", contentType: "application/javascript", err: ErrInvalidContentType},
{name: "content-type/xml", apikey: "apikey", dataset: "dataset", contentType: "application/xml", err: ErrInvalidContentType},
Expand Down
Loading