<commit_before>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package validation

import (
	"context"
	"reflect"
	"regexp"
	"sync"
	"time"

	"github.com/golang/protobuf/ptypes"
	"google.golang.org/genproto/googleapis/devtools/cloudtrace/v2"
	genprotoStatus "google.golang.org/genproto/googleapis/rpc/status"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

const (
	// These restrictions can be found at
	// https://cloud.google.com/trace/docs/reference/v2/rpc/google.devtools.cloudtrace.v2
	maxAnnotationAttributes = 4
	maxAnnotationBytes      = 256
	maxAttributes           = 32
	maxAttributeKeyBytes    = 128
	maxAttributeValueBytes  = 256
	maxDisplayNameBytes     = 128
	maxLinks                = 128
	maxTimeEvents           = 32

	agent          = "g.co/agent"
	shortenedAgent = "agent"
)

var (
	// The exporter is responsible for mapping these special attributes to the correct
	// canonical Cloud Trace attributes (/http/method, /http/route, etc.)
	specialAttributes = map[string]struct{}{
		"http.method":      {},
		"http.route":       {},
		"http.status_code": {},
	}
	requiredFields = []string{"Name", "SpanId", "DisplayName", "StartTime", "EndTime"}
	spanNameRegex  = regexp.MustCompile("^projects/[^/]+/traces/[a-fA-F0-9]{32}/spans/[a-fA-F0-9]{16}$")
	agentRegex     = regexp.MustCompile(`^opentelemetry-[a-zA-Z]+ [0-9]+\.[0-9]+\.[0-9]+; google-cloud-trace-exporter [0-9]+\.[0-9]+\.[0-9]+$`)
)

// SpanData wraps all the span data on the server into a struct.
type SpanData struct {
	// If a batch has a bad span, we don't write batch to memory, but still want
	// info on them for summary, so need SpansSummary
	SpansSummary      []*cloudtrace.Span
	UploadedSpanNames map[string]struct{}
	UploadedSpans     []*cloudtrace.Span
	Mutex             sync.RWMutex
}

// ValidateSpans checks that the spans conform to the API requirements.
// That is, required fields are present, and optional fields are of the correct form.
// If any violations are detected, the errors will be added to the result table.
func ValidateSpans(requestName string, spanData *SpanData, spans ...*cloudtrace.Span) error {
	var overallError error
	currentRequestSpanNames := make(map[string]struct{})

	for _, span := range spans {
		var currentError error

		// Validate required fields are present and semantically make sense.<commit_msg>Loosen regex for agent attribute (#55)<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package validation

import (
	"context"
	"reflect"
	"regexp"
	"sync"
	"time"

	"github.com/golang/protobuf/ptypes"
	"google.golang.org/genproto/googleapis/devtools/cloudtrace/v2"
	genprotoStatus "google.golang.org/genproto/googleapis/rpc/status"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

const (
	// These restrictions can be found at
	// https://cloud.google.com/trace/docs/reference/v2/rpc/google.devtools.cloudtrace.v2
	maxAnnotationAttributes = 4
	maxAnnotationBytes      = 256
	maxAttributes           = 32
	maxAttributeKeyBytes    = 128
	maxAttributeValueBytes  = 256
	maxDisplayNameBytes     = 128
	maxLinks                = 128
	maxTimeEvents           = 32

	agent          = "g.co/agent"
	shortenedAgent = "agent"
)

var (
	// The exporter is responsible for mapping these special attributes to the correct
	// canonical Cloud Trace attributes (/http/method, /http/route, etc.)
	specialAttributes = map[string]struct{}{
		"http.method":      {},
		"http.route":       {},
		"http.status_code": {},
	}
	requiredFields = []string{"Name", "SpanId", "DisplayName", "StartTime", "EndTime"}
	spanNameRegex  = regexp.MustCompile("^projects/[^/]+/traces/[a-fA-F0-9]{32}/spans/[a-fA-F0-9]{16}$")
	agentRegex     = regexp.MustCompile(`^opentelemetry-[a-zA-Z]+ \d+(?:\.\d+)+; google-cloud-trace-exporter \d+(?:\.\d+)+$`)
)

// SpanData wraps all the span data on the server into a struct.
type SpanData struct {
	// If a batch has a bad span, we don't write batch to memory, but still want
	// info on them for summary, so need SpansSummary
	SpansSummary      []*cloudtrace.Span
	UploadedSpanNames map[string]struct{}
	UploadedSpans     []*cloudtrace.Span
	Mutex             sync.RWMutex
}

// ValidateSpans checks that the spans conform to the API requirements.
// That is, required fields are present, and optional fields are of the correct form.
// If any violations are detected, the errors will be added to the result table.
func ValidateSpans(requestName string, spanData *SpanData, spans ...*cloudtrace.Span) error {
	var overallError error
	currentRequestSpanNames := make(map[string]struct{})

	for _, span := range spans {
		var currentError error

		// Validate required fields are present and semantically make sense.
{'fraction_non_alphanumeric': 0.11792207792207793, 'fraction_numerical': 0.01593073593073593, 'mean_word_length': 3.540880503144654, 'pattern_counts': {'":': 6, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 4, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1551388', 'n_tokens_mistral': 1840, 'n_tokens_neox': 1730, 'n_words': 558}