Skip to content

Commit 5520798

Browse files
authored
[pkg/translator/azure] Allow timestamp to be used instead of time (#28805)
**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.--> Allow the attribute 'timestamp' to be used as an alternative to the documented 'time'. **Link to tracking Issue:** <Issue number if applicable> [#28806] **Testing:** <Describe what testing was performed and which tests were added.> Using the example from Azure I created a unit test. **Documentation:** <Describe the documentation added.> Note added to Azure Event Hub Receiver.
1 parent de8ba78 commit 5520798

File tree

5 files changed

+149
-3
lines changed

5 files changed

+149
-3
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: bug_fix
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
7+
component: azuretranslatorpkg
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: When receiving data from Azure some data does not meet the Common Specifications when sending the timestamp. Allow the attribute timeStamp to be used as an alternative to the standard time.
11+
12+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
13+
issues: [28806]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext:
19+
20+
# If your change doesn't affect end users or the exported elements of any package,
21+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
22+
# Optional: The change log or logs in which this entry should be included.
23+
# e.g. '[user]' or '[user, api]'
24+
# Include 'user' if the change is relevant to end users.
25+
# Include 'api' if there is a change to a library API.
26+
# Default: '[user]'
27+
change_logs: []

pkg/translator/azure/resourcelogs_to_logs.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package azure // import "github.com/open-telemetry/opentelemetry-collector-contr
66
import (
77
"bytes"
88
"encoding/json"
9+
"errors"
910
"strconv"
1011

1112
jsoniter "github.com/json-iterator/go"
@@ -36,6 +37,10 @@ const (
3637
azureTenantID = "azure.tenant.id"
3738
)
3839

40+
var (
41+
errMissingTimestamp = errors.New("missing timestamp")
42+
)
43+
3944
// azureRecords represents an array of Azure log records
4045
// as exported via an Azure Event Hub
4146
type azureRecords struct {
@@ -47,6 +52,7 @@ type azureRecords struct {
4752
// https://learn.microsoft.com/en-us/azure/azure-monitor/essentials/resource-logs-schema
4853
type azureLogRecord struct {
4954
Time string `json:"time"`
55+
Timestamp string `json:"timeStamp"`
5056
ResourceID string `json:"resourceId"`
5157
TenantID *string `json:"tenantId"`
5258
OperationName string `json:"operationName"`
@@ -101,7 +107,7 @@ func (r ResourceLogsUnmarshaler) UnmarshalLogs(buf []byte) (plog.Logs, error) {
101107

102108
for i := 0; i < len(logs); i++ {
103109
log := logs[i]
104-
nanos, err := asTimestamp(log.Time)
110+
nanos, err := getTimestamp(log)
105111
if err != nil {
106112
r.Logger.Warn("Unable to convert timestamp from log", zap.String("timestamp", log.Time))
107113
continue
@@ -125,6 +131,16 @@ func (r ResourceLogsUnmarshaler) UnmarshalLogs(buf []byte) (plog.Logs, error) {
125131
return l, nil
126132
}
127133

134+
func getTimestamp(record azureLogRecord) (pcommon.Timestamp, error) {
135+
if record.Time != "" {
136+
return asTimestamp(record.Time)
137+
} else if record.Timestamp != "" {
138+
return asTimestamp(record.Timestamp)
139+
}
140+
141+
return 0, errMissingTimestamp
142+
}
143+
128144
// asTimestamp will parse an ISO8601 string into an OpenTelemetry
129145
// nanosecond timestamp. If the string cannot be parsed, it will
130146
// return zero and the error.
@@ -133,6 +149,7 @@ func asTimestamp(s string) (pcommon.Timestamp, error) {
133149
if err != nil {
134150
return 0, err
135151
}
152+
136153
return pcommon.Timestamp(t.UnixNano()), nil
137154
}
138155

pkg/translator/azure/resourcelogs_to_logs_test.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,49 @@ var badLevelLogRecord = func() plog.LogRecord {
167167
return lr
168168
}()
169169

170+
var badTimeLogRecord = func() plog.LogRecord {
171+
lr := plog.NewLogs().ResourceLogs().AppendEmpty().ScopeLogs().AppendEmpty().LogRecords().AppendEmpty()
172+
173+
ts, _ := asTimestamp("2021-10-14T22:17:11+00:00")
174+
lr.SetTimestamp(ts)
175+
176+
lr.Attributes().PutStr(azureOperationName, "ApplicationGatewayAccess")
177+
lr.Attributes().PutStr(azureCategory, "ApplicationGatewayAccessLog")
178+
lr.Attributes().PutStr(conventions.AttributeCloudProvider, conventions.AttributeCloudProviderAzure)
179+
180+
m := lr.Attributes().PutEmptyMap(azureProperties)
181+
m.PutStr("instanceId", "appgw_2")
182+
m.PutStr("clientIP", "185.42.129.24")
183+
m.PutDouble("clientPort", 45057)
184+
m.PutStr("httpMethod", "GET")
185+
m.PutStr("originalRequestUriWithArgs", "/")
186+
m.PutStr("requestUri", "/")
187+
m.PutStr("requestQuery", "")
188+
m.PutStr("userAgent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36")
189+
m.PutDouble("httpStatus", 200)
190+
m.PutStr("httpVersion", "HTTP/1.1")
191+
m.PutDouble("receivedBytes", 184)
192+
m.PutDouble("sentBytes", 466)
193+
m.PutDouble("clientResponseTime", 0)
194+
m.PutDouble("timeTaken", 0.034)
195+
m.PutStr("WAFEvaluationTime", "0.000")
196+
m.PutStr("WAFMode", "Detection")
197+
m.PutStr("transactionId", "592d1649f75a8d480a3c4dc6a975309d")
198+
m.PutStr("sslEnabled", "on")
199+
m.PutStr("sslCipher", "ECDHE-RSA-AES256-GCM-SHA384")
200+
m.PutStr("sslProtocol", "TLSv1.2")
201+
m.PutStr("sslClientVerify", "NONE")
202+
m.PutStr("sslClientCertificateFingerprint", "")
203+
m.PutStr("sslClientCertificateIssuerName", "")
204+
m.PutStr("serverRouted", "52.239.221.65:443")
205+
m.PutStr("serverStatus", "200")
206+
m.PutStr("serverResponseLatency", "0.028")
207+
m.PutStr("upstreamSourcePort", "21564")
208+
m.PutStr("originalHost", "20.110.30.194")
209+
m.PutStr("host", "20.110.30.194")
210+
return lr
211+
}()
212+
170213
func TestAsTimestamp(t *testing.T) {
171214
timestamp := "2022-11-11T04:48:27.6767145Z"
172215
nanos, err := asTimestamp(timestamp)
@@ -371,6 +414,15 @@ func TestUnmarshalLogs(t *testing.T) {
371414
lr = scopeLogs.LogRecords().AppendEmpty()
372415
badLevelLogRecord.CopyTo(lr)
373416

417+
expectedBadTime := plog.NewLogs()
418+
resourceLogs = expectedBadTime.ResourceLogs().AppendEmpty()
419+
resourceLogs.Resource().Attributes().PutStr(azureResourceID, "/RESOURCE_ID")
420+
scopeLogs = resourceLogs.ScopeLogs().AppendEmpty()
421+
scopeLogs.Scope().SetName("otelcol/azureresourcelogs")
422+
scopeLogs.Scope().SetVersion(testBuildInfo.Version)
423+
lr = scopeLogs.LogRecords().AppendEmpty()
424+
badTimeLogRecord.CopyTo(lr)
425+
374426
tests := []struct {
375427
file string
376428
expected plog.Logs
@@ -391,6 +443,10 @@ func TestUnmarshalLogs(t *testing.T) {
391443
file: "log-bad-level.json",
392444
expected: expectedBadLevel,
393445
},
446+
{
447+
file: "log-bad-time.json",
448+
expected: expectedBadTime,
449+
},
394450
}
395451

396452
sut := &ResourceLogsUnmarshaler{
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{
2+
"records": [
3+
{
4+
"timeStamp": "2021-10-14T22:17:11+00:00",
5+
"resourceId": "/RESOURCE_ID",
6+
"listenerName": "HTTP-Listener",
7+
"ruleName": "Storage-Static-Rule",
8+
"backendPoolName": "StaticStorageAccount",
9+
"backendSettingName": "StorageStatic-HTTPS-Setting",
10+
"operationName": "ApplicationGatewayAccess",
11+
"category": "ApplicationGatewayAccessLog",
12+
"properties": {
13+
"instanceId": "appgw_2",
14+
"clientIP": "185.42.129.24",
15+
"clientPort": 45057,
16+
"httpMethod": "GET",
17+
"originalRequestUriWithArgs": "\/",
18+
"requestUri": "\/",
19+
"requestQuery": "",
20+
"userAgent": "Mozilla\/5.0 (Windows NT 6.1; WOW64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/52.0.2743.116 Safari\/537.36",
21+
"httpStatus": 200,
22+
"httpVersion": "HTTP\/1.1",
23+
"receivedBytes": 184,
24+
"sentBytes": 466,
25+
"clientResponseTime": 0,
26+
"timeTaken": 0.034,
27+
"WAFEvaluationTime": "0.000",
28+
"WAFMode": "Detection",
29+
"transactionId": "592d1649f75a8d480a3c4dc6a975309d",
30+
"sslEnabled": "on",
31+
"sslCipher": "ECDHE-RSA-AES256-GCM-SHA384",
32+
"sslProtocol": "TLSv1.2",
33+
"sslClientVerify": "NONE",
34+
"sslClientCertificateFingerprint": "",
35+
"sslClientCertificateIssuerName": "",
36+
"serverRouted": "52.239.221.65:443",
37+
"serverStatus": "200",
38+
"serverResponseLatency": "0.028",
39+
"upstreamSourcePort": "21564",
40+
"originalHost": "20.110.30.194",
41+
"host": "20.110.30.194"
42+
}
43+
}
44+
]
45+
}

receiver/azureeventhubreceiver/README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,11 @@ and the OpenTelemetry attributes.
9595
| resultSignature (optional) | azure.result.signature (attribute) |
9696
| resultType (optional) | azure.result.type (attribute) |
9797
| tenantId (required, tenant logs) | azure.tenant.id (attribute) |
98-
| time (required) | time_unix_nano (field) |
98+
| time or timeStamp (required) | time_unix_nano (time takes precedence) |
9999
| identity (optional) | azure.identity (attribute, nested) |
100100
101-
Note: JSON does not distinguish between fixed and floating point numbers. All
101+
Notes:
102+
* JSON does not distinguish between fixed and floating point numbers. All
102103
JSON numbers are encoded as doubles.
103104
104105
For Metrics the Azure Metric Records are an array

0 commit comments

Comments
 (0)