|
| 1 | +package manager |
| 2 | + |
| 3 | +import ( |
| 4 | + "fmt" |
| 5 | + "os" |
| 6 | + "strings" |
| 7 | + |
| 8 | + "github.com/spf13/cobra" |
| 9 | + "go.opentelemetry.io/otel" |
| 10 | + "go.opentelemetry.io/otel/attribute" |
| 11 | + "go.opentelemetry.io/otel/baggage" |
| 12 | +) |
| 13 | + |
| 14 | +const ( |
| 15 | + // resourceAttributesEnvVar is the name of the envvar that includes additional |
| 16 | + // resource attributes for OTEL as defined in the [OpenTelemetry specification]. |
| 17 | + // |
| 18 | + // [OpenTelemetry specification]: https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/#general-sdk-configuration |
| 19 | + resourceAttributesEnvVar = "OTEL_RESOURCE_ATTRIBUTES" |
| 20 | + |
| 21 | + // dockerCLIAttributePrefix is the prefix for any docker cli OTEL attributes. |
| 22 | + // |
| 23 | + // It is a copy of the const defined in [command.dockerCLIAttributePrefix]. |
| 24 | + dockerCLIAttributePrefix = "docker.cli." |
| 25 | + cobraCommandPath = attribute.Key("cobra.command_path") |
| 26 | +) |
| 27 | + |
| 28 | +func getPluginResourceAttributes(cmd *cobra.Command, plugin Plugin) attribute.Set { |
| 29 | + commandPath := cmd.Annotations[CommandAnnotationPluginCommandPath] |
| 30 | + if commandPath == "" { |
| 31 | + commandPath = fmt.Sprintf("%s %s", cmd.CommandPath(), plugin.Name) |
| 32 | + } |
| 33 | + |
| 34 | + attrSet := attribute.NewSet( |
| 35 | + cobraCommandPath.String(commandPath), |
| 36 | + ) |
| 37 | + |
| 38 | + kvs := make([]attribute.KeyValue, 0, attrSet.Len()) |
| 39 | + for iter := attrSet.Iter(); iter.Next(); { |
| 40 | + attr := iter.Attribute() |
| 41 | + kvs = append(kvs, attribute.KeyValue{ |
| 42 | + Key: dockerCLIAttributePrefix + attr.Key, |
| 43 | + Value: attr.Value, |
| 44 | + }) |
| 45 | + } |
| 46 | + return attribute.NewSet(kvs...) |
| 47 | +} |
| 48 | + |
| 49 | +func appendPluginResourceAttributesEnvvar(env []string, cmd *cobra.Command, plugin Plugin) []string { |
| 50 | + if attrs := getPluginResourceAttributes(cmd, plugin); attrs.Len() > 0 { |
| 51 | + // Construct baggage members for each of the attributes. |
| 52 | + // Ignore any failures as these aren't significant and |
| 53 | + // represent an internal issue. |
| 54 | + members := make([]baggage.Member, 0, attrs.Len()) |
| 55 | + for iter := attrs.Iter(); iter.Next(); { |
| 56 | + attr := iter.Attribute() |
| 57 | + m, err := baggage.NewMemberRaw(string(attr.Key), attr.Value.AsString()) |
| 58 | + if err != nil { |
| 59 | + otel.Handle(err) |
| 60 | + continue |
| 61 | + } |
| 62 | + members = append(members, m) |
| 63 | + } |
| 64 | + |
| 65 | + // Combine plugin added resource attributes with ones found in the environment |
| 66 | + // variable. Our own attributes should be namespaced so there shouldn't be a |
| 67 | + // conflict. We do not parse the environment variable because we do not want |
| 68 | + // to handle errors in user configuration. |
| 69 | + attrsSlice := make([]string, 0, 2) |
| 70 | + if v := strings.TrimSpace(os.Getenv(resourceAttributesEnvVar)); v != "" { |
| 71 | + attrsSlice = append(attrsSlice, v) |
| 72 | + } |
| 73 | + if b, err := baggage.New(members...); err != nil { |
| 74 | + otel.Handle(err) |
| 75 | + } else if b.Len() > 0 { |
| 76 | + attrsSlice = append(attrsSlice, b.String()) |
| 77 | + } |
| 78 | + |
| 79 | + if len(attrsSlice) > 0 { |
| 80 | + env = append(env, resourceAttributesEnvVar+"="+strings.Join(attrsSlice, ",")) |
| 81 | + } |
| 82 | + } |
| 83 | + return env |
| 84 | +} |
0 commit comments