Skip to content

Commit ec58812

Browse files
authored
Introduce "split" metric schema transformation (#2999)
This is a new transformation type that allows to describe a change where a metric is converted to several other metrics by eliminating an attribute. An example of such change that happened recently is this: open-telemetry/opentelemetry-specification#2617 This PR implements specification change open-telemetry/opentelemetry-specification#2653 This PR creates package v1.1 for the new functionality. The old package v1.0 remains unchanged.
1 parent ed329a9 commit ec58812

14 files changed

+741
-153
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
2626

2727
- Add support for `opentracing.TextMap` format in the `Inject` and `Extract` methods
2828
of the `"go.opentelemetry.io/otel/bridge/opentracing".BridgeTracer` type. (#2911)
29+
- Add support for Schema Files format 1.1.x (metric "split" transform). (#2999)
2930

3031
### Changed
3132

schema/README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ then import the corresponding package and use the `Parse` or `ParseFile` functio
1111
like this:
1212

1313
```go
14-
import schema "go.opentelemetry.io/otel/schema/v1.0"
14+
import schema "go.opentelemetry.io/otel/schema/v1.1"
1515

16-
// Load the schema from a file in v1.0.x file format.
16+
// Load the schema from a file in v1.1.x file format.
1717
func loadSchemaFromFile() error {
1818
telSchema, err := schema.ParseFile("schema-file.yaml")
1919
if err != nil {

schema/internal/parser_checks.go

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// Copyright The OpenTelemetry Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package internal // import "go.opentelemetry.io/otel/schema/internal"
16+
17+
import (
18+
"errors"
19+
"fmt"
20+
"net/url"
21+
"strconv"
22+
"strings"
23+
24+
"github.com/Masterminds/semver/v3"
25+
)
26+
27+
// CheckFileFormatField validates the file format field according to the rules here:
28+
// https://github.com/open-telemetry/oteps/blob/main/text/0152-telemetry-schemas.md#schema-file-format-number
29+
func CheckFileFormatField(fileFormat string, supportedFormatMajor, supportedFormatMinor int) error {
30+
// Verify that the version number in the file is a semver.
31+
fileFormatParsed, err := semver.StrictNewVersion(fileFormat)
32+
if err != nil {
33+
return fmt.Errorf(
34+
"invalid schema file format version number %q (expected semver): %w",
35+
fileFormat, err,
36+
)
37+
}
38+
39+
// Check that the major version number in the file is the same as what we expect.
40+
if fileFormatParsed.Major() != uint64(supportedFormatMajor) {
41+
return fmt.Errorf(
42+
"this library cannot parse file formats with major version other than %v",
43+
supportedFormatMajor,
44+
)
45+
}
46+
47+
// Check that the file minor version number is not greater than
48+
// what is requested supports.
49+
if fileFormatParsed.Minor() > uint64(supportedFormatMinor) {
50+
supportedFormatMajorMinor := strconv.Itoa(supportedFormatMajor) + "." +
51+
strconv.Itoa(supportedFormatMinor) // 1.0
52+
53+
return fmt.Errorf(
54+
"unsupported schema file format minor version number, expected no newer than %v, got %v",
55+
supportedFormatMajorMinor+".x", fileFormat,
56+
)
57+
}
58+
59+
// Patch, prerelease and metadata version number does not matter, so we don't check it.
60+
61+
return nil
62+
}
63+
64+
// CheckSchemaURL verifies that schemaURL is valid.
65+
func CheckSchemaURL(schemaURL string) error {
66+
if strings.TrimSpace(schemaURL) == "" {
67+
return errors.New("schema_url field is missing")
68+
}
69+
70+
if _, err := url.Parse(schemaURL); err != nil {
71+
return fmt.Errorf("invalid URL specified in schema_url field: %w", err)
72+
}
73+
return nil
74+
}

schema/internal/parser_checks_test.go

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright The OpenTelemetry Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package internal // import "go.opentelemetry.io/otel/schema/internal"
16+
17+
import (
18+
"testing"
19+
20+
"github.com/stretchr/testify/assert"
21+
)
22+
23+
func TestCheckFileFormatField(t *testing.T) {
24+
// Invalid file format version numbers.
25+
assert.Error(t, CheckFileFormatField("not a semver", 1, 0))
26+
assert.Error(t, CheckFileFormatField("2.0.0", 1, 0))
27+
assert.Error(t, CheckFileFormatField("1.1.0", 1, 0))
28+
29+
assert.Error(t, CheckFileFormatField("1.2.0", 1, 1))
30+
31+
// Valid cases.
32+
assert.NoError(t, CheckFileFormatField("1.0.0", 1, 0))
33+
assert.NoError(t, CheckFileFormatField("1.0.1", 1, 0))
34+
assert.NoError(t, CheckFileFormatField("1.0.10000-alpha+4857", 1, 0))
35+
36+
assert.NoError(t, CheckFileFormatField("1.0.0", 1, 1))
37+
assert.NoError(t, CheckFileFormatField("1.0.1", 1, 1))
38+
assert.NoError(t, CheckFileFormatField("1.0.10000-alpha+4857", 1, 1))
39+
assert.NoError(t, CheckFileFormatField("1.1.0", 1, 1))
40+
assert.NoError(t, CheckFileFormatField("1.1.1", 1, 1))
41+
}

schema/v1.0/parser.go

+6-50
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,12 @@
1515
package schema // import "go.opentelemetry.io/otel/schema/v1.0"
1616

1717
import (
18-
"fmt"
1918
"io"
20-
"net/url"
2119
"os"
22-
"strconv"
23-
"strings"
2420

25-
"github.com/Masterminds/semver/v3"
2621
"gopkg.in/yaml.v2"
2722

23+
"go.opentelemetry.io/otel/schema/internal"
2824
"go.opentelemetry.io/otel/schema/v1.0/ast"
2925
)
3026

@@ -34,10 +30,6 @@ const supportedFormatMajor = 1
3430
// Maximum minor version number that this library supports.
3531
const supportedFormatMinor = 0
3632

37-
// Maximum major+minor version number that this library supports, as a string.
38-
var supportedFormatMajorMinor = strconv.Itoa(supportedFormatMajor) + "." +
39-
strconv.Itoa(supportedFormatMinor) // 1.0
40-
4133
// ParseFile a schema file. schemaFilePath is the file path.
4234
func ParseFile(schemaFilePath string) (*ast.Schema, error) {
4335
file, err := os.Open(schemaFilePath)
@@ -56,51 +48,15 @@ func Parse(schemaFileContent io.Reader) (*ast.Schema, error) {
5648
return nil, err
5749
}
5850

59-
if err := checkFileFormatField(ts.FileFormat); err != nil {
51+
err = internal.CheckFileFormatField(ts.FileFormat, supportedFormatMajor, supportedFormatMinor)
52+
if err != nil {
6053
return nil, err
6154
}
6255

63-
if strings.TrimSpace(ts.SchemaURL) == "" {
64-
return nil, fmt.Errorf("schema_url field is missing")
65-
}
66-
67-
if _, err := url.Parse(ts.SchemaURL); err != nil {
68-
return nil, fmt.Errorf("invalid URL specified in schema_url field: %w", err)
69-
}
70-
71-
return &ts, nil
72-
}
73-
74-
// checkFileFormatField validates the file format field according to the rules here:
75-
// https://github.com/open-telemetry/oteps/blob/main/text/0152-telemetry-schemas.md#schema-file-format-number
76-
func checkFileFormatField(fileFormat string) error {
77-
// Verify that the version number in the file is a semver.
78-
fileFormatParsed, err := semver.StrictNewVersion(fileFormat)
56+
err = internal.CheckSchemaURL(ts.SchemaURL)
7957
if err != nil {
80-
return fmt.Errorf(
81-
"invalid schema file format version number %q (expected semver): %w",
82-
fileFormat, err,
83-
)
84-
}
85-
86-
// Check that the major version number in the file is the same as what we expect.
87-
if fileFormatParsed.Major() != supportedFormatMajor {
88-
return fmt.Errorf(
89-
"this library cannot parse file formats with major version other than %v",
90-
supportedFormatMajor,
91-
)
92-
}
93-
94-
// Check that the file minor version number is not greater than
95-
// what is requested supports.
96-
if fileFormatParsed.Minor() > supportedFormatMinor {
97-
return fmt.Errorf(
98-
"unsupported schema file format minor version number, expected no newer than %v, got %v",
99-
supportedFormatMajorMinor+".x", fileFormat,
100-
)
58+
return nil, err
10159
}
10260

103-
// Patch, prerelease and metadata version number does not matter, so we don't check it.
104-
105-
return nil
61+
return &ts, nil
10662
}

0 commit comments

Comments
 (0)