Skip to content

Commit

Permalink
fix(mc2mc): query builder override values + setup metrics collector (#54
Browse files Browse the repository at this point in the history
)

* refactor: otel attributes

* refactor: config

* fix: otel attributes

* fix: overrided values on query builder
  • Loading branch information
deryrahman authored Dec 24, 2024
1 parent 7ac22b6 commit cc49017
Show file tree
Hide file tree
Showing 10 changed files with 179 additions and 129 deletions.
18 changes: 11 additions & 7 deletions mc2mc/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@ go 1.22.3

require (
github.com/aliyun/aliyun-odps-go-sdk v0.3.15
github.com/caarlos0/env/v11 v11.3.1
github.com/pkg/errors v0.9.1
github.com/stretchr/testify v1.9.0
go.opentelemetry.io/otel v1.30.0
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.10.0
go.opentelemetry.io/contrib/instrumentation/runtime v0.58.0
go.opentelemetry.io/otel v1.33.0
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.30.0
go.opentelemetry.io/otel/sdk v1.30.0
go.opentelemetry.io/otel/sdk/metric v1.30.0
go.opentelemetry.io/otel/sdk v1.33.0
go.opentelemetry.io/otel/sdk/metric v1.33.0
)

require (
Expand All @@ -30,12 +33,13 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pierrec/lz4/v4 v4.1.18 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
go.opentelemetry.io/otel/metric v1.30.0 // indirect
go.opentelemetry.io/otel/trace v1.30.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/otel/metric v1.33.0 // indirect
go.opentelemetry.io/otel/trace v1.33.0 // indirect
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect
golang.org/x/net v0.29.0 // indirect
golang.org/x/sys v0.25.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/text v0.18.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240924160255-9d4c2d233b61 // indirect
Expand Down
40 changes: 24 additions & 16 deletions mc2mc/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ github.com/aliyun/credentials-go v1.3.10/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPT
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/caarlos0/env/v11 v11.3.1 h1:cArPWC15hWmEt+gWk7YBi7lEXTXCvpaSdCiZE2X5mCA=
github.com/caarlos0/env/v11 v11.3.1/go.mod h1:qupehSf/Y0TUTsxKywqRt/vJjN5nz6vauiYEUUr8P4U=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
Expand Down Expand Up @@ -129,10 +131,12 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w=
github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
Expand All @@ -143,22 +147,26 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts=
go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/runtime v0.58.0 h1:GrcF8ABgnBHQFgp4zu5/jTSqLkoJ9uiDz2e7eKkjq+w=
go.opentelemetry.io/contrib/instrumentation/runtime v0.58.0/go.mod h1:+kxR5prZLoFAJVXJWZKWO2e4PY2dYyXIRNklBuOyzpM=
go.opentelemetry.io/otel v1.33.0 h1:/FerN9bax5LoK51X/sI0SVYrjSE0/yUL7DpxW4K3FWw=
go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.30.0 h1:WypxHH02KX2poqqbaadmkMYalGyy/vil4HE4PM4nRJc=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.30.0/go.mod h1:U79SV99vtvGSEBeeHnpgGJfTsnsdkWLpPN/CcHAzBSI=
go.opentelemetry.io/otel/metric v1.30.0 h1:4xNulvn9gjzo4hjg+wzIKG7iNFEaBMX00Qd4QIZs7+w=
go.opentelemetry.io/otel/metric v1.30.0/go.mod h1:aXTfST94tswhWEb+5QjlSqG+cZlmyXy/u8jFpor3WqQ=
go.opentelemetry.io/otel/sdk v1.30.0 h1:cHdik6irO49R5IysVhdn8oaiR9m8XluDaJAs4DfOrYE=
go.opentelemetry.io/otel/sdk v1.30.0/go.mod h1:p14X4Ok8S+sygzblytT1nqG98QG2KYKv++HE0LY/mhg=
go.opentelemetry.io/otel/sdk/metric v1.30.0 h1:QJLT8Pe11jyHBHfSAgYH7kEmT24eX792jZO1bo4BXkM=
go.opentelemetry.io/otel/sdk/metric v1.30.0/go.mod h1:waS6P3YqFNzeP01kuo/MBBYqaoBJl7efRQHOaydhy1Y=
go.opentelemetry.io/otel/trace v1.30.0 h1:7UBkkYzeg3C7kQX8VAidWh2biiQbtAKjyIML8dQ9wmc=
go.opentelemetry.io/otel/trace v1.30.0/go.mod h1:5EyKqTzzmyqB9bwtCCq6pDLktPK6fmGf/Dph+8VI02o=
go.opentelemetry.io/otel/metric v1.33.0 h1:r+JOocAyeRVXD8lZpjdQjzMadVZp2M4WmQ+5WtEnklQ=
go.opentelemetry.io/otel/metric v1.33.0/go.mod h1:L9+Fyctbp6HFTddIxClbQkjtubW6O9QS3Ann/M82u6M=
go.opentelemetry.io/otel/sdk v1.33.0 h1:iax7M131HuAm9QkZotNHEfstof92xM+N8sr3uHXc2IM=
go.opentelemetry.io/otel/sdk v1.33.0/go.mod h1:A1Q5oi7/9XaMlIWzPSxLRWOI8nG3FnzHJNbiENQuihM=
go.opentelemetry.io/otel/sdk/metric v1.33.0 h1:Gs5VK9/WUJhNXZgn8MR6ITatvAmKeIuCtNbsP3JkNqU=
go.opentelemetry.io/otel/sdk/metric v1.33.0/go.mod h1:dL5ykHZmm1B1nVRk9dDjChwDmt81MjVp3gLkQRwKf/Q=
go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s=
go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
Expand Down Expand Up @@ -247,8 +255,8 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
Expand Down
20 changes: 15 additions & 5 deletions mc2mc/internal/client/opentelemetry.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@ package client

import (
"context"
"time"

"github.com/pkg/errors"
"go.opentelemetry.io/contrib/instrumentation/runtime"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc"
"go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/resource"
)

func setupOTelSDK(ctx context.Context, collectorGRPCEndpoint string, jobName, scheduledTime string) (shutdown func() error, err error) {
// SetupOTelSDK sets up the OpenTelemetry SDK.
func setupOTelSDK(ctx context.Context, collectorGRPCEndpoint string, attributes map[string]string) (shutdown func() error, err error) {
metricExporter, err := otlpmetricgrpc.New(ctx,
otlpmetricgrpc.WithEndpoint(collectorGRPCEndpoint),
otlpmetricgrpc.WithInsecure(),
Expand All @@ -20,18 +23,25 @@ func setupOTelSDK(ctx context.Context, collectorGRPCEndpoint string, jobName, sc
return nil, errors.WithStack(err)
}

attr := []attribute.KeyValue{}
for k, v := range attributes {
attr = append(attr, attribute.String(k, v))
}

// for now, we only need metric provider
meterProvider := metric.NewMeterProvider(
metric.WithResource(resource.NewWithAttributes(
resource.Default().SchemaURL(),
attribute.String("plugin.name", "mc2mc"),
attribute.String("job.name", jobName),
attribute.String("job.scheduled_time", scheduledTime),
attr...,
)),
metric.WithReader(metric.NewPeriodicReader(metricExporter)),
metric.WithReader(metric.NewPeriodicReader(metricExporter, metric.WithInterval(5*time.Second))),
)
otel.SetMeterProvider(meterProvider)

// start runtime metrics collection
// this will collect metrics like memory usage, goroutines, etc.
runtime.Start(runtime.WithMinimumReadMemStatsInterval(1 * time.Second))

return func() error {
return meterProvider.Shutdown(context.Background())
}, nil
Expand Down
13 changes: 11 additions & 2 deletions mc2mc/internal/client/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package client

import (
"log/slog"
"strings"

"github.com/aliyun/aliyun-odps-go-sdk/odps"
"github.com/pkg/errors"
Expand All @@ -23,12 +24,20 @@ func SetupODPSClient(odpsClient *odps.Odps) SetupFn {
}
}

func SetupOTelSDK(collectorGRPCEndpoint, jobName, scheduledTime string) SetupFn {
func SetupOTelSDK(collectorGRPCEndpoint string, otelAttributes string) SetupFn {
return func(c *Client) error {
if collectorGRPCEndpoint == "" {
return nil
}
shutdownFn, err := setupOTelSDK(c.appCtx, collectorGRPCEndpoint, jobName, scheduledTime)
attrSlice := strings.Split(otelAttributes, ",")
attr := make(map[string]string, len(attrSlice))
for _, a := range attrSlice {
kv := strings.Split(a, "=")
if len(kv) == 2 {
attr[kv[0]] = kv[1]
}
}
shutdownFn, err := setupOTelSDK(c.appCtx, collectorGRPCEndpoint, attr)
if err != nil {
return errors.WithStack(err)
}
Expand Down
72 changes: 33 additions & 39 deletions mc2mc/internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,61 +7,55 @@ import (
"github.com/pkg/errors"
)

type Config struct {
*odps.Config
LogLevel string
LoadMethod string
QueryFilePath string
DestinationTableID string
OtelCollectorGRPCEndpoint string
JobName string
ScheduledTime string
DStart string
// TODO: remove this temporary support after 15 nov 2024
DevEnablePartitionValue bool
DevEnableAutoPartition bool
// ConfigEnv is a mc configuration for the component.
type ConfigEnv struct {
LogLevel string `env:"LOG_LEVEL" envDefault:"INFO"`
OtelCollectorGRPCEndpoint string `env:"OTEL_COLLECTOR_GRPC_ENDPOINT"`
OtelAttributes string `env:"OTEL_ATTRIBUTES"`
MCServiceAccount string `env:"MC_SERVICE_ACCOUNT"`
LoadMethod string `env:"LOAD_METHOD" envDefault:"APPEND"`
QueryFilePath string `env:"QUERY_FILE_PATH" envDefault:"/data/in/query.sql"`
DestinationTableID string `env:"DESTINATION_TABLE_ID"`
DStart string `env:"DSTART"`
// TODO: delete this
DevEnablePartitionValue string `env:"DEV__ENABLE_PARTITION_VALUE" envDefault:"false"`
DevEnableAutoPartition string `env:"DEV__ENABLE_AUTO_PARTITION" envDefault:"false"`
}

type maxComputeCredentials struct {
AccessId string `json:"access_id"`
AccessKey string `json:"access_key"`
Endpoint string `json:"endpoint"`
ProjectName string `json:"project_name"`
type Config struct {
*odps.Config
*ConfigEnv
}

func NewConfig() (*Config, error) {
cfg := &Config{
Config: odps.NewConfig(),
// mc2mc related config
LogLevel: getEnv("LOG_LEVEL", "INFO"),
LoadMethod: getEnv("LOAD_METHOD", "APPEND"),
QueryFilePath: getEnv("QUERY_FILE_PATH", "/data/in/query.sql"),
DestinationTableID: getEnv("DESTINATION_TABLE_ID", ""),
// system related config
OtelCollectorGRPCEndpoint: getEnv("OTEL_COLLECTOR_GRPC_ENDPOINT", ""),
JobName: getJobName(),
ScheduledTime: getEnv("SCHEDULED_TIME", ""),
DStart: getEnv("DSTART", ""),
// TODO: delete this after 15 nov
DevEnablePartitionValue: getEnv("DEV__ENABLE_PARTITION_VALUE", "false") == "true",
DevEnableAutoPartition: getEnv("DEV__ENABLE_AUTO_PARTITION", "false") == "true",
// NewConfig parses the environment variables and returns the mc configuration.
func NewConfig(envs ...string) (*Config, error) {
configEnv, err := parse[ConfigEnv](envs...)
if err != nil {
return nil, errors.WithStack(err)
}
// ali-odps-go-sdk related config
scvAcc := getEnv("MC_SERVICE_ACCOUNT", "")
cred, err := collectMaxComputeCredential([]byte(scvAcc))
cred, err := collectMaxComputeCredential([]byte(configEnv.MCServiceAccount))
if err != nil {
return nil, errors.WithStack(err)
}
cfg := &Config{
Config: &odps.Config{},
ConfigEnv: configEnv,
}
cfg.Config.AccessId = cred.AccessId
cfg.Config.AccessKey = cred.AccessKey
cfg.Config.Endpoint = cred.Endpoint
cfg.Config.ProjectName = cred.ProjectName
cfg.Config.HttpTimeout = getEnvDuration("MC_HTTP_TIMEOUT", "10s")
cfg.Config.TcpConnectionTimeout = getEnvDuration("MC_TCP_TIMEOUT", "30s")

return cfg, nil
}

type maxComputeCredentials struct {
AccessId string `json:"access_id"`
AccessKey string `json:"access_key"`
Endpoint string `json:"endpoint"`
ProjectName string `json:"project_name"`
}

func collectMaxComputeCredential(scvAcc []byte) (*maxComputeCredentials, error) {
var creds maxComputeCredentials
if err := json.Unmarshal(scvAcc, &creds); err != nil {
Expand Down
56 changes: 32 additions & 24 deletions mc2mc/internal/config/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,45 @@ package config
import (
"os"
"strings"
"time"

"github.com/caarlos0/env/v11"
)

func getEnv(key, fallback string) string {
if value, ok := os.LookupEnv(key); ok {
return value
}
return fallback
}
// parse parses the environment variables and returns the configuration.
func parse[T any](envs ...string) (*T, error) {
env0 := toMap(os.Environ())
env1 := toMap(envs)

func getEnvDuration(key, fallback string) time.Duration {
result, _ := time.ParseDuration(getEnv(key, fallback))
return result
c, err := env.ParseAsWithOptions[T](env.Options{
Environment: mergeMaps(env0, env1),
})
if err != nil {
return nil, err
}
return &c, nil
}

// specific to parse job name from JOB_LABELS environment variable
// later on this should be refactored properly
func getJobName() string {
return parseLabels("job_name")
// toMap converts the environment variables to a map.
// for example "KEY=VALUE" to map["KEY"] = "VALUE".
func toMap(env []string) map[string]string {
r := map[string]string{}
for _, e := range env {
p := strings.SplitN(e, "=", 2)
if len(p) == 2 {
r[p[0]] = p[1]
}
}
return r
}

// specific parsing for JOB_LABELS environment variable
// later on this should be refactored properly
func parseLabels(key string) string {
labels := strings.Split(getEnv("JOB_LABELS", ""), ",")
// parse label from JOB_LABELS based on key
for _, label := range labels {
parsed := strings.Split(label, "=")
if len(parsed) == 2 && parsed[0] == key {
return parsed[1]
// mergeMaps merges multiple maps into one.
// If there are duplicate keys, the value from the last map will be used.
func mergeMaps(maps ...map[string]string) map[string]string {
r := map[string]string{}
for _, m := range maps {
for k, v := range m {
r[k] = v
}
}
return ""
return r
}
Loading

0 comments on commit cc49017

Please sign in to comment.