Skip to content

Commit

Permalink
moved json/yaml unmarshaling into their own files
Browse files Browse the repository at this point in the history
This will give us more flexibility to ensure unmarshaling in both yaml/json
returns a consistent structure.

Signed-off-by: Alex Boten <[email protected]>
  • Loading branch information
codeboten committed Oct 9, 2024
1 parent ffe8eef commit b3e322f
Show file tree
Hide file tree
Showing 5 changed files with 419 additions and 348 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,7 @@ genjsonschema: genjsonschema-cleanup $(GOJSONSCHEMA)
--capitalization OTLP \
--struct-name-from-title \
--package config \
--only-models \
--output ${GENERATED_CONFIG} \
${OPENTELEMETRY_CONFIGURATION_JSONSCHEMA_SRC_DIR}/schema/opentelemetry_configuration.json
@echo Modify jsonschema generated files.
Expand Down
374 changes: 374 additions & 0 deletions config/config_json.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,374 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package config // import "go.opentelemetry.io/contrib/config"

import (
"encoding/json"
"fmt"
"reflect"
)

// MarshalJSON implements json.Marshaler.
func (j *AttributeNameValueType) MarshalJSON() ([]byte, error) {
return json.Marshal(j.Value)
}

var enumValuesAttributeNameValueType = []interface{}{
nil,
"string",
"bool",
"int",
"double",
"string_array",
"bool_array",
"int_array",
"double_array",
}

// UnmarshalJSON implements json.Unmarshaler.
func (j *AttributeNameValueType) UnmarshalJSON(b []byte) error {
var v struct {
Value interface{}
}
if err := json.Unmarshal(b, &v.Value); err != nil {
return err
}
var ok bool
for _, expected := range enumValuesAttributeNameValueType {
if reflect.DeepEqual(v.Value, expected) {
ok = true
break
}
}
if !ok {
return fmt.Errorf("invalid value (expected one of %#v): %#v", enumValuesAttributeNameValueType, v.Value)
}
*j = AttributeNameValueType(v)
return nil
}

// UnmarshalJSON implements json.Unmarshaler.
func (j *BatchLogRecordProcessor) UnmarshalJSON(b []byte) error {
var raw map[string]interface{}
if err := json.Unmarshal(b, &raw); err != nil {
return err
}
if _, ok := raw["exporter"]; raw != nil && !ok {
return fmt.Errorf("field exporter in BatchLogRecordProcessor: required")
}
type Plain BatchLogRecordProcessor
var plain Plain
if err := json.Unmarshal(b, &plain); err != nil {
return err
}
*j = BatchLogRecordProcessor(plain)
return nil
}

// UnmarshalJSON implements json.Unmarshaler.
func (j *BatchSpanProcessor) UnmarshalJSON(b []byte) error {
var raw map[string]interface{}
if err := json.Unmarshal(b, &raw); err != nil {
return err
}
if _, ok := raw["exporter"]; raw != nil && !ok {
return fmt.Errorf("field exporter in BatchSpanProcessor: required")
}
type Plain BatchSpanProcessor
var plain Plain
if err := json.Unmarshal(b, &plain); err != nil {
return err
}
*j = BatchSpanProcessor(plain)
return nil
}

// UnmarshalJSON implements json.Unmarshaler.
func (j *GeneralInstrumentationPeerServiceMappingElem) UnmarshalJSON(b []byte) error {
var raw map[string]interface{}
if err := json.Unmarshal(b, &raw); err != nil {
return err
}
if _, ok := raw["peer"]; raw != nil && !ok {
return fmt.Errorf("field peer in GeneralInstrumentationPeerServiceMappingElem: required")
}
if _, ok := raw["service"]; raw != nil && !ok {
return fmt.Errorf("field service in GeneralInstrumentationPeerServiceMappingElem: required")
}
type Plain GeneralInstrumentationPeerServiceMappingElem
var plain Plain
if err := json.Unmarshal(b, &plain); err != nil {
return err
}
*j = GeneralInstrumentationPeerServiceMappingElem(plain)
return nil
}

// UnmarshalJSON implements json.Unmarshaler.
func (j *NameStringValuePair) UnmarshalJSON(b []byte) error {
var raw map[string]interface{}
if err := json.Unmarshal(b, &raw); err != nil {
return err
}
if _, ok := raw["name"]; raw != nil && !ok {
return fmt.Errorf("field name in NameStringValuePair: required")
}
if _, ok := raw["value"]; raw != nil && !ok {
return fmt.Errorf("field value in NameStringValuePair: required")
}
type Plain NameStringValuePair
var plain Plain
if err := json.Unmarshal(b, &plain); err != nil {
return err
}
*j = NameStringValuePair(plain)
return nil
}

var enumValuesOTLPMetricDefaultHistogramAggregation = []interface{}{
"explicit_bucket_histogram",
"base2_exponential_bucket_histogram",
}

// UnmarshalJSON implements json.Unmarshaler.
func (j *OTLPMetricDefaultHistogramAggregation) UnmarshalJSON(b []byte) error {
var v string
if err := json.Unmarshal(b, &v); err != nil {
return err
}
var ok bool
for _, expected := range enumValuesOTLPMetricDefaultHistogramAggregation {
if reflect.DeepEqual(v, expected) {
ok = true
break
}
}
if !ok {
return fmt.Errorf("invalid value (expected one of %#v): %#v", enumValuesOTLPMetricDefaultHistogramAggregation, v)
}
*j = OTLPMetricDefaultHistogramAggregation(v)
return nil
}

// UnmarshalJSON implements json.Unmarshaler.
func (j *OTLPMetric) UnmarshalJSON(b []byte) error {
var raw map[string]interface{}
if err := json.Unmarshal(b, &raw); err != nil {
return err
}
if _, ok := raw["endpoint"]; raw != nil && !ok {
return fmt.Errorf("field endpoint in OTLPMetric: required")
}
if _, ok := raw["protocol"]; raw != nil && !ok {
return fmt.Errorf("field protocol in OTLPMetric: required")
}
type Plain OTLPMetric
var plain Plain
if err := json.Unmarshal(b, &plain); err != nil {
return err
}
*j = OTLPMetric(plain)
return nil
}

// UnmarshalJSON implements json.Unmarshaler.
func (j *OTLP) UnmarshalJSON(b []byte) error {
var raw map[string]interface{}
if err := json.Unmarshal(b, &raw); err != nil {
return err
}
if _, ok := raw["endpoint"]; raw != nil && !ok {
return fmt.Errorf("field endpoint in OTLP: required")
}
if _, ok := raw["protocol"]; raw != nil && !ok {
return fmt.Errorf("field protocol in OTLP: required")
}
type Plain OTLP
var plain Plain
if err := json.Unmarshal(b, &plain); err != nil {
return err
}
*j = OTLP(plain)
return nil
}

// UnmarshalJSON implements json.Unmarshaler.
func (j *OpenTelemetryConfiguration) UnmarshalJSON(b []byte) error {
var raw map[string]interface{}
if err := json.Unmarshal(b, &raw); err != nil {
return err
}
if _, ok := raw["file_format"]; raw != nil && !ok {
return fmt.Errorf("field file_format in OpenTelemetryConfiguration: required")
}
type Plain OpenTelemetryConfiguration
var plain Plain
if err := json.Unmarshal(b, &plain); err != nil {
return err
}
*j = OpenTelemetryConfiguration(plain)
return nil
}

// UnmarshalJSON implements json.Unmarshaler.
func (j *PeriodicMetricReader) UnmarshalJSON(b []byte) error {
var raw map[string]interface{}
if err := json.Unmarshal(b, &raw); err != nil {
return err
}
if _, ok := raw["exporter"]; raw != nil && !ok {
return fmt.Errorf("field exporter in PeriodicMetricReader: required")
}
type Plain PeriodicMetricReader
var plain Plain
if err := json.Unmarshal(b, &plain); err != nil {
return err
}
*j = PeriodicMetricReader(plain)
return nil
}

// UnmarshalJSON implements json.Unmarshaler.
func (j *PullMetricReader) UnmarshalJSON(b []byte) error {
var raw map[string]interface{}
if err := json.Unmarshal(b, &raw); err != nil {
return err
}
if _, ok := raw["exporter"]; raw != nil && !ok {
return fmt.Errorf("field exporter in PullMetricReader: required")
}
type Plain PullMetricReader
var plain Plain
if err := json.Unmarshal(b, &plain); err != nil {
return err
}
*j = PullMetricReader(plain)
return nil
}

// UnmarshalJSON implements json.Unmarshaler.
func (j *SimpleLogRecordProcessor) UnmarshalJSON(b []byte) error {
var raw map[string]interface{}
if err := json.Unmarshal(b, &raw); err != nil {
return err
}
if _, ok := raw["exporter"]; raw != nil && !ok {
return fmt.Errorf("field exporter in SimpleLogRecordProcessor: required")
}
type Plain SimpleLogRecordProcessor
var plain Plain
if err := json.Unmarshal(b, &plain); err != nil {
return err
}
*j = SimpleLogRecordProcessor(plain)
return nil
}

// UnmarshalJSON implements json.Unmarshaler.
func (j *SimpleSpanProcessor) UnmarshalJSON(b []byte) error {
var raw map[string]interface{}
if err := json.Unmarshal(b, &raw); err != nil {
return err
}
if _, ok := raw["exporter"]; raw != nil && !ok {
return fmt.Errorf("field exporter in SimpleSpanProcessor: required")
}
type Plain SimpleSpanProcessor
var plain Plain
if err := json.Unmarshal(b, &plain); err != nil {
return err
}
*j = SimpleSpanProcessor(plain)
return nil
}

var enumValuesViewSelectorInstrumentType = []interface{}{
"counter",
"histogram",
"observable_counter",
"observable_gauge",
"observable_up_down_counter",
"up_down_counter",
}

// UnmarshalJSON implements json.Unmarshaler.
func (j *ViewSelectorInstrumentType) UnmarshalJSON(b []byte) error {
var v string
if err := json.Unmarshal(b, &v); err != nil {
return err
}
var ok bool
for _, expected := range enumValuesViewSelectorInstrumentType {
if reflect.DeepEqual(v, expected) {
ok = true
break
}
}
if !ok {
return fmt.Errorf("invalid value (expected one of %#v): %#v", enumValuesViewSelectorInstrumentType, v)
}
*j = ViewSelectorInstrumentType(v)
return nil
}

// UnmarshalJSON implements json.Unmarshaler.
func (j *Zipkin) UnmarshalJSON(b []byte) error {
var raw map[string]interface{}
if err := json.Unmarshal(b, &raw); err != nil {
return err
}
if _, ok := raw["endpoint"]; raw != nil && !ok {
return fmt.Errorf("field endpoint in Zipkin: required")
}
type Plain Zipkin
var plain Plain
if err := json.Unmarshal(b, &plain); err != nil {
return err
}
*j = Zipkin(plain)
return nil
}

// UnmarshalJSON implements json.Unmarshaler.
func (j *AttributeNameValue) UnmarshalJSON(b []byte) error {
var raw map[string]interface{}
if err := json.Unmarshal(b, &raw); err != nil {
return err
}
if _, ok := raw["name"]; raw != nil && !ok {
return fmt.Errorf("field name in AttributeNameValue: required")
}
if _, ok := raw["value"]; raw != nil && !ok {
return fmt.Errorf("field value in AttributeNameValue: required")
}
type Plain AttributeNameValue
var plain Plain
if err := json.Unmarshal(b, &plain); err != nil {
return err
}
if plain.Type != nil && plain.Type.Value == "int" {
val, ok := plain.Value.(float64)
if ok {
plain.Value = int(val)
}
}
if plain.Type != nil && plain.Type.Value == "int_array" {
m, ok := plain.Value.([]interface{})
if ok {
var vals []interface{}
for _, v := range m {
val, ok := v.(float64)
if ok {
vals = append(vals, int(val))
} else {
vals = append(vals, val)
}
}
plain.Value = vals
}
}

*j = AttributeNameValue(plain)
return nil
}
4 changes: 2 additions & 2 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -291,11 +291,11 @@ var v03OpenTelemetryConfig = OpenTelemetryConfiguration{
{Name: "service.name", Value: "unknown_service"},
{Name: "string_key", Type: &AttributeNameValueType{Value: "string"}, Value: "value"},
{Name: "bool_key", Type: &AttributeNameValueType{Value: "bool"}, Value: true},
{Name: "int_key", Type: &AttributeNameValueType{Value: "int"}, Value: float64(1)},
{Name: "int_key", Type: &AttributeNameValueType{Value: "int"}, Value: 1},
{Name: "double_key", Type: &AttributeNameValueType{Value: "double"}, Value: 1.1},
{Name: "string_array_key", Type: &AttributeNameValueType{Value: "string_array"}, Value: []interface{}{"value1", "value2"}},
{Name: "bool_array_key", Type: &AttributeNameValueType{Value: "bool_array"}, Value: []interface{}{true, false}},
{Name: "int_array_key", Type: &AttributeNameValueType{Value: "int_array"}, Value: []interface{}{float64(1), float64(2)}},
{Name: "int_array_key", Type: &AttributeNameValueType{Value: "int_array"}, Value: []interface{}{1, 2}},
{Name: "double_array_key", Type: &AttributeNameValueType{Value: "double_array"}, Value: []interface{}{1.1, 2.2}},
},
AttributesList: ptr("service.namespace=my-namespace,service.version=1.0.0"),
Expand Down
Loading

0 comments on commit b3e322f

Please sign in to comment.