Skip to content

Commit

Permalink
Add SHA512 converter. (open-telemetry#34050)
Browse files Browse the repository at this point in the history
**Description:** <Describe what has changed.>
<!--Ex. Fixing a bug - Describe the bug and how this fixes the issue.
Ex. Adding a feature - Explain what this achieves.-->
Adds a converter to generate SHA-512 digest. See the open-telemetry#34007 issue for
more details.

**Link to tracking Issue:** open-telemetry#34007 

**Testing:**
- Unit testing
- E2E
- Local testing
- after applying changes, build `opentelemetry-collector-contrib`: `cd
opentelemetry-collector-contrib && make otelcontribcol`
- create config folder and place following config under
`otel-transform-sha512.yaml` file:
    ```
    extensions:
      zpages:
        endpoint: 127.0.0.1:55679

    receivers:
      otlp:
        protocols:
          http:
            endpoint: 127.0.0.1:8080

    processors:
      batch:
      transform:
        log_statements:
          - context: log
            statements:
- set(attributes["string.attribute"],
SHA512(attributes["string.attribute"]))

    exporters:
      debug:
        verbosity: detailed
      elasticsearch:
        hosts: ["localhost:9200"]
        user: "elastic"
        password: "changeme"
        index: "otel-collector-sha256"

    service:
      telemetry:
        logs:
          level: debug
      pipelines:
        logs:
          receivers: [otlp]
          processors: [batch, transform]
          exporters: [elasticsearch, debug]

      extensions: [zpages]
    ```
- run otel collector: `bin/otelcontribcol_darwin_amd64
--config=config/otel-transform-sha512.yaml`
  - send data
     ```
        curl --location '127.0.0.1:8080/v1/logs' \
    --header 'Content-Type: application/json' \
    --data '{
      "resourceLogs": [
        {
          "resource": {
            "attributes": [
              {
                "key": "service.name",
                "value": {
                  "stringValue": "my.service"
                }
              }
            ]
          },
          "scopeLogs": [
            {
              "scope": {
                "name": "my.library",
                "version": "1.0.0",
                "attributes": [
                  {
                    "key": "my.scope.attribute",
                    "value": {
                      "stringValue": "some scope attribute"
                    }
                  }
                ]
              },
              "logRecords": [
                {
                  "timeUnixNano": "1544712660300000000",
                  "observedTimeUnixNano": "1544712660300000000",
                  "severityNumber": 10,
                  "severityText": "Information",
                  "traceId": "5B8EFFF798038103D269B633813FC60C",
                  "spanId": "EEE19B7EC3C1B174",
                  "body": {
                    "stringValue": "Example log record"
                  },
                  "attributes": [
                    {
                      "key": "string.attribute",
                      "value": {
                        "stringValue": "sending some data for SHA512"
                      }
                    },
                    {
                      "key": "boolean.attribute",
                      "value": {
                        "boolValue": true
                      }
                    },
                    {
                      "key": "int.attribute",
                      "value": {
                        "intValue": "10"
                      }
                    },
                    {
                      "key": "double.attribute",
                      "value": {
                        "doubleValue": 637.704
                      }
                    },
                    {
                      "key": "array.attribute",
                      "value": {
                        "arrayValue": {
                          "values": [
                            {
                              "stringValue": "many"
                            },
                            {
                              "stringValue": "values"
                            }
                          ]
                        }
                      }
                    },
                    {
                      "key": "map.attribute",
                      "value": {
                        "kvlistValue": {
                          "values": [
                            {
                              "key": "some.map.key",
                              "value": {
                                "stringValue": "some value"
                              }
                            }
                          ]
                        }
                      }
                    }
                  ]
                }
              ]
            }
          ]
        }
      ]
    }'
    ``` 
  - you will be able to see SHA512 value on console
    ```
    ObservedTimestamp: 2018-12-13 14:51:00.3 +0000 UTC
    Timestamp: 2018-12-13 14:51:00.3 +0000 UTC
    SeverityText: Information
    SeverityNumber: Info2(10)
    Body: Str(Example log record)
    Attributes:
-> string.attribute:
Str(6cbe75a224033d0f145fd67e02cab35ce42a10cd1aa7b7030dd74e31af97037f2020d063305bc2552d1b9e43ca15872ea248c5b236df98085c690932a7f0ea49)
         -> boolean.attribute: Bool(true)
         -> int.attribute: Int(10)
         -> double.attribute: Double(637.704)
         -> array.attribute: Slice(["many","values"])
         -> map.attribute: Map({"some.map.key":"some value"})
    Trace ID: 5b8efff798038103d269b633813fc60c
    Span ID: eee19b7ec3c1b174
    ```
**Documentation:**
- Added to OTTL readme and changelogs generated. Let me please know if I
am missing any doc references.
  • Loading branch information
mashhurs authored Aug 6, 2024
1 parent d647f91 commit 3cadc39
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 0 deletions.
27 changes: 27 additions & 0 deletions .chloggen/ottl_sha512_converter.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Use this changelog template to create an entry for release notes.

# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: 'enhancement'

# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
component: pkg/ottl

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: Introduce `sha512` converter to generate SHA-512 hash/digest from given payload.

# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
issues: [34007]

# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext:

# If your change doesn't affect end users or the exported elements of any package,
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
# Optional: The change log or logs in which this entry should be included.
# e.g. '[user]' or '[user, api]'
# Include 'user' if the change is relevant to end users.
# Include 'api' if there is a change to a library API.
# Default: '[user]'
change_logs: []
6 changes: 6 additions & 0 deletions pkg/ottl/e2e/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -619,6 +619,12 @@ func Test_e2e_converters(t *testing.T) {
tCtx.GetLogRecord().Attributes().PutStr("test", "d74ff0ee8da3b9806b18c877dbf29bbde50b5bd8e4dad7a3a725000feb82e8f1")
},
},
{
statement: `set(attributes["test"], SHA512("pass"))`,
want: func(tCtx ottllog.TransformContext) {
tCtx.GetLogRecord().Attributes().PutStr("test", "5b722b307fce6c944905d132691d5e4a2214b7fe92b738920eb3fce3a90420a19511c3010a0e7712b054daef5b57bad59ecbd93b3280f210578f547f4aed4d25")
},
},
{
statement: `set(span_id, SpanID(0x0000000000000000))`,
want: func(tCtx ottllog.TransformContext) {
Expand Down
18 changes: 18 additions & 0 deletions pkg/ottl/ottlfuncs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,7 @@ Available Converters:
- [Seconds](#seconds)
- [SHA1](#sha1)
- [SHA256](#sha256)
- [SHA512](#sha512)
- [SpanID](#spanid)
- [Split](#split)
- [String](#string)
Expand Down Expand Up @@ -1206,6 +1207,23 @@ Examples:

- `SHA256("name")`

### SHA512

`SHA512(input)`

The `SHA512` converter calculates sha512 hash value/digest of the `input`.

The returned type is string.

`input` is either a path expression to a string telemetry field or a literal string. If `input` is another type, converter raises an error.
If an error occurs during hashing, the error will be returned.

Examples:

- `SHA512(attributes["device.name"])`

- `SHA512("name")`

### SpanID

`SpanID(bytes)`
Expand Down
48 changes: 48 additions & 0 deletions pkg/ottl/ottlfuncs/func_sha512.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package ottlfuncs // import "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/ottlfuncs"

import (
"context"
"crypto/sha512"
"encoding/hex"
"fmt"

"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
)

type SHA512Arguments[K any] struct {
Target ottl.StringGetter[K]
}

func NewSHA512Factory[K any]() ottl.Factory[K] {
return ottl.NewFactory("SHA512", &SHA512Arguments[K]{}, createSHA512Function[K])
}

func createSHA512Function[K any](_ ottl.FunctionContext, oArgs ottl.Arguments) (ottl.ExprFunc[K], error) {
args, ok := oArgs.(*SHA512Arguments[K])

if !ok {
return nil, fmt.Errorf("SHA512Factory args must be of type *SHA512Arguments[K]")
}

return SHA512HashString(args.Target)
}

func SHA512HashString[K any](target ottl.StringGetter[K]) (ottl.ExprFunc[K], error) {

return func(ctx context.Context, tCtx K) (any, error) {
val, err := target.Get(ctx, tCtx)
if err != nil {
return nil, err
}
hash := sha512.New()
_, err = hash.Write([]byte(val))
if err != nil {
return nil, err
}
hashValue := hex.EncodeToString(hash.Sum(nil))
return hashValue, nil
}, nil
}
82 changes: 82 additions & 0 deletions pkg/ottl/ottlfuncs/func_sha512_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package ottlfuncs

import (
"context"
"testing"

"github.com/stretchr/testify/assert"

"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
)

func Test_SHA512(t *testing.T) {
tests := []struct {
name string
value any
expected any
err bool
}{
{
name: "empty string",
value: "",
expected: "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e",
},
{
name: "string",
value: "foo bar",
expected: "65019286222ace418f742556366f9b9da5aaf6797527d2f0cba5bfe6b2f8ed24746542a0f2be1da8d63c2477f688b608eb53628993afa624f378b03f10090ce7",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
exprFunc, err := SHA512HashString[any](&ottl.StandardStringGetter[any]{
Getter: func(context.Context, any) (any, error) {
return tt.value, nil
},
})
assert.NoError(t, err)
result, err := exprFunc(nil, nil)
if tt.err {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
assert.Equal(t, tt.expected, result)
})
}
}

func Test_SHA512Error(t *testing.T) {
tests := []struct {
name string
value any
err bool
expectedError string
}{
{
name: "non-string",
value: 10,
expectedError: "expected string but got int",
},
{
name: "nil",
value: nil,
expectedError: "expected string but got nil",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
exprFunc, err := SHA512HashString[any](&ottl.StandardStringGetter[any]{
Getter: func(context.Context, any) (any, error) {
return tt.value, nil
},
})
assert.NoError(t, err)
_, err = exprFunc(nil, nil)
assert.ErrorContains(t, err, tt.expectedError)
})
}
}
1 change: 1 addition & 0 deletions pkg/ottl/ottlfuncs/functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ func converters[K any]() []ottl.Factory[K] {
NewSecondsFactory[K](),
NewSHA1Factory[K](),
NewSHA256Factory[K](),
NewSHA512Factory[K](),
NewSpanIDFactory[K](),
NewSplitFactory[K](),
NewFormatFactory[K](),
Expand Down

0 comments on commit 3cadc39

Please sign in to comment.