Skip to content

Commit 1b2e63c

Browse files
authored
Merge branch 'main' into main
2 parents be0da30 + ee50355 commit 1b2e63c

File tree

12 files changed

+368
-315
lines changed

12 files changed

+368
-315
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: 'breaking'
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
7+
component: splunkenterprisereceiver
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: "disabled default metrics except for splunkHealth to ensure scrapes run on Splunk instance are opt-in"
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: [39068]
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: [user]

.chloggen/vpc-optimization.yaml

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: enhancement
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
7+
component: awslogsencodingextension
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Improve performance when unmarshalling plain-text VPC flow logs.
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: [39043]
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: []
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
version account-id interface-id srcaddr dstaddr srcport dstport protocol packets bytes start end action log-status
2+
2 12345678910 eni-0eb1e4178af74336c - - - - - - - 1742570089 1742570142 - NODATA one-too-many

extension/encoding/awslogsencodingextension/internal/unmarshaler/vpc-flow-log/vpc_flow_log_unmarshaler.go

Lines changed: 84 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,12 @@ func (v *vpcFlowLogUnmarshaler) UnmarshalLogs(content []byte) (plog.Logs, error)
9797
}
9898
}
9999

100+
// resourceKey stores the account id and region
101+
// of the flow logs. All log lines inside the
102+
// same S3 file come from the same account and
103+
// region.
104+
//
105+
// See https://docs.aws.amazon.com/vpc/latest/userguide/flow-logs-s3-path.html.
100106
type resourceKey struct {
101107
accountID string
102108
region string
@@ -111,10 +117,11 @@ func (v *vpcFlowLogUnmarshaler) unmarshalPlainTextLogs(reader io.Reader) (plog.L
111117
fields = strings.Split(firstLine, " ")
112118
}
113119

114-
scopeLogsByResource := map[resourceKey]plog.ScopeLogs{}
120+
logs, resourceLogs, scopeLogs := v.createLogs()
121+
key := &resourceKey{}
115122
for scanner.Scan() {
116123
line := scanner.Text()
117-
if err := v.addToLogs(scopeLogsByResource, fields, line); err != nil {
124+
if err := v.addToLogs(key, scopeLogs, fields, line); err != nil {
118125
return plog.Logs{}, err
119126
}
120127
}
@@ -123,70 +130,64 @@ func (v *vpcFlowLogUnmarshaler) unmarshalPlainTextLogs(reader io.Reader) (plog.L
123130
return plog.Logs{}, fmt.Errorf("error reading log line: %w", err)
124131
}
125132

126-
return v.createLogs(scopeLogsByResource), nil
133+
v.setResourceAttributes(key, resourceLogs)
134+
return logs, nil
127135
}
128136

129-
// createLogs based on the scopeLogsByResource map
130-
func (v *vpcFlowLogUnmarshaler) createLogs(scopeLogsByResource map[resourceKey]plog.ScopeLogs) plog.Logs {
137+
// createLogs with the expected fields for the scope logs
138+
func (v *vpcFlowLogUnmarshaler) createLogs() (plog.Logs, plog.ResourceLogs, plog.ScopeLogs) {
131139
logs := plog.NewLogs()
140+
resourceLogs := logs.ResourceLogs().AppendEmpty()
141+
scopeLogs := resourceLogs.ScopeLogs().AppendEmpty()
142+
scopeLogs.Scope().SetName(metadata.ScopeName)
143+
scopeLogs.Scope().SetVersion(v.buildInfo.Version)
144+
return logs, resourceLogs, scopeLogs
145+
}
132146

133-
for key, scopeLogs := range scopeLogsByResource {
134-
rl := logs.ResourceLogs().AppendEmpty()
135-
attr := rl.Resource().Attributes()
136-
attr.PutStr(conventions.AttributeCloudProvider, conventions.AttributeCloudProviderAWS)
137-
if key.accountID != "" {
138-
attr.PutStr(conventions.AttributeCloudAccountID, key.accountID)
139-
}
140-
if key.region != "" {
141-
attr.PutStr(conventions.AttributeCloudRegion, key.region)
142-
}
143-
scopeLogs.MoveTo(rl.ScopeLogs().AppendEmpty())
147+
// setResourceAttributes based on the resourceKey
148+
func (v *vpcFlowLogUnmarshaler) setResourceAttributes(key *resourceKey, logs plog.ResourceLogs) {
149+
attr := logs.Resource().Attributes()
150+
attr.PutStr(conventions.AttributeCloudProvider, conventions.AttributeCloudProviderAWS)
151+
if key.accountID != "" {
152+
attr.PutStr(conventions.AttributeCloudAccountID, key.accountID)
153+
}
154+
if key.region != "" {
155+
attr.PutStr(conventions.AttributeCloudRegion, key.region)
144156
}
157+
}
145158

146-
return logs
159+
// address stores the four fields related to the address
160+
// of a VPC flow log: srcaddr, pkt-srcaddr, dstaddr, and
161+
// pkt-dstaddr. We save these fields in a struct, so we
162+
// can use the right naming conventions in the end.
163+
//
164+
// See https://docs.aws.amazon.com/vpc/latest/userguide/flow-logs-records-examples.html#flow-log-example-nat.
165+
type address struct {
166+
source string
167+
pktSource string
168+
destination string
169+
pktDestination string
147170
}
148171

149172
// addToLogs parses the log line and creates
150173
// a new record log. The record log is added
151174
// to the scope logs of the resource identified
152175
// by the resourceKey created from the values.
153176
func (v *vpcFlowLogUnmarshaler) addToLogs(
154-
scopeLogsByResource map[resourceKey]plog.ScopeLogs,
177+
key *resourceKey,
178+
scopeLogs plog.ScopeLogs,
155179
fields []string,
156180
logLine string,
157181
) error {
158-
// first line includes the fields
159-
// TODO Replace with an iterator starting from go 1.24:
160-
// https://pkg.go.dev/strings#FieldsSeq
161-
nFields := len(fields)
162-
nValues := strings.Count(logLine, " ") + 1
163-
if nFields != nValues {
164-
return fmt.Errorf("expect %d fields per log line, got log line with %d fields", nFields, nValues)
165-
}
166-
167-
// create new key for resource and new
168-
// log record to add to the scope of logs
169-
// of the resource
170-
key := &resourceKey{}
171182
record := plog.NewLogRecord()
172183

173-
// There are 4 fields for the addresses: srcaddr, pkt-srcaddr,
174-
// dstaddr, pkt-dstaddr. We will save these fields in a
175-
// map, so we can use the right conventions in the end.
176-
//
177-
// See https://docs.aws.amazon.com/vpc/latest/userguide/flow-logs-records-examples.html#flow-log-example-nat.
178-
ips := make(map[string]string, 4)
179-
180-
start := 0
184+
addr := &address{}
181185
for _, field := range fields {
182-
var value string
183-
end := strings.Index(logLine[start:], " ")
184-
if end == -1 {
185-
value = logLine[start:]
186-
} else {
187-
value = logLine[start : start+end]
188-
start += end + 1 // skip the space
186+
if logLine == "" {
187+
return errors.New("log line has less fields than the ones expected")
189188
}
189+
var value string
190+
value, logLine, _ = strings.Cut(logLine, " ")
190191

191192
if value == "-" {
192193
// If a field is not applicable or could not be computed for a
@@ -201,7 +202,7 @@ func (v *vpcFlowLogUnmarshaler) addToLogs(
201202
continue
202203
}
203204

204-
found, err := handleField(field, value, record, ips, key)
205+
found, err := handleField(field, value, record, addr, key)
205206
if err != nil {
206207
return err
207208
}
@@ -213,70 +214,51 @@ func (v *vpcFlowLogUnmarshaler) addToLogs(
213214
}
214215
}
215216

216-
// get the address fields
217-
addresses := v.handleAddresses(ips)
218-
for field, value := range addresses {
219-
record.Attributes().PutStr(field, value)
217+
if logLine != "" {
218+
return errors.New("log line has more fields than the ones expected")
220219
}
221220

222-
scopeLogs := v.getScopeLogs(*key, scopeLogsByResource)
221+
// add the address fields with the correct conventions
222+
// to the log record
223+
v.handleAddresses(addr, record)
223224
rScope := scopeLogs.LogRecords().AppendEmpty()
224225
record.MoveTo(rScope)
225226

226227
return nil
227228
}
228229

229-
// handleAddresses creates a new map where the original field
230-
// names will be the known conventions for the fields
231-
func (v *vpcFlowLogUnmarshaler) handleAddresses(addresses map[string]string) map[string]string {
232-
// max is 3 fields, see example in
230+
// handleAddresses creates adds the addresses to the log record
231+
func (v *vpcFlowLogUnmarshaler) handleAddresses(addr *address, record plog.LogRecord) {
232+
localAddrSet := false
233+
// see example in
233234
// https://docs.aws.amazon.com/vpc/latest/userguide/flow-logs-records-examples.html#flow-log-example-nat
234-
recordAttr := make(map[string]string, 3)
235-
srcaddr, foundSrc := addresses["srcaddr"]
236-
pktSrcaddr, foundSrcPkt := addresses["pkt-srcaddr"]
237-
if !foundSrcPkt && foundSrc {
235+
if addr.pktSource == "" && addr.source != "" {
238236
// there is no middle layer, assume "srcaddr" field
239237
// corresponds to the original source address.
240-
recordAttr[conventions.AttributeSourceAddress] = srcaddr
241-
} else if foundSrcPkt && foundSrc {
242-
recordAttr[conventions.AttributeSourceAddress] = pktSrcaddr
243-
if srcaddr != pktSrcaddr {
238+
record.Attributes().PutStr(conventions.AttributeSourceAddress, addr.source)
239+
} else if addr.pktSource != "" && addr.source != "" {
240+
record.Attributes().PutStr(conventions.AttributeSourceAddress, addr.pktSource)
241+
if addr.pktSource != addr.source {
244242
// srcaddr is the middle layer
245-
recordAttr[conventions.AttributeNetworkPeerAddress] = srcaddr
243+
record.Attributes().PutStr(conventions.AttributeNetworkLocalAddress, addr.source)
244+
localAddrSet = true
246245
}
247246
}
248247

249-
dstaddr, foundDst := addresses["dstaddr"]
250-
pktDstaddr, foundDstPkt := addresses["pkt-dstaddr"]
251-
if !foundDstPkt && foundDst {
248+
if addr.pktDestination == "" && addr.destination != "" {
252249
// there is no middle layer, assume "dstaddr" field
253250
// corresponds to the original destination address.
254-
recordAttr[conventions.AttributeDestinationAddress] = dstaddr
255-
} else if foundDstPkt && foundDst {
256-
recordAttr[conventions.AttributeDestinationAddress] = pktDstaddr
257-
if pktDstaddr != dstaddr {
258-
if _, found := recordAttr[conventions.AttributeNetworkPeerAddress]; found {
251+
record.Attributes().PutStr(conventions.AttributeDestinationAddress, addr.destination)
252+
} else if addr.pktDestination != "" && addr.destination != "" {
253+
record.Attributes().PutStr(conventions.AttributeDestinationAddress, addr.pktDestination)
254+
if addr.pktDestination != addr.destination {
255+
if localAddrSet {
259256
v.logger.Warn("unexpected: srcaddr, dstaddr, pkt-srcaddr and pkt-dstaddr are all different")
260257
}
261258
// dstaddr is the middle layer
262-
recordAttr[conventions.AttributeNetworkPeerAddress] = dstaddr
259+
record.Attributes().PutStr(conventions.AttributeNetworkLocalAddress, addr.destination)
263260
}
264261
}
265-
266-
return recordAttr
267-
}
268-
269-
// getScopeLogs for the given key. If it does not exist yet,
270-
// create new scope logs, and add the key to the logs map.
271-
func (v *vpcFlowLogUnmarshaler) getScopeLogs(key resourceKey, logs map[resourceKey]plog.ScopeLogs) plog.ScopeLogs {
272-
scopeLogs, ok := logs[key]
273-
if !ok {
274-
scopeLogs = plog.NewScopeLogs()
275-
scopeLogs.Scope().SetName(metadata.ScopeName)
276-
scopeLogs.Scope().SetVersion(v.buildInfo.Version)
277-
logs[key] = scopeLogs
278-
}
279-
return scopeLogs
280262
}
281263

282264
// handleField analyzes the given field and it either
@@ -287,7 +269,7 @@ func handleField(
287269
field string,
288270
value string,
289271
record plog.LogRecord,
290-
ips map[string]string,
272+
addr *address,
291273
key *resourceKey,
292274
) (bool, error) {
293275
// convert string to number
@@ -312,9 +294,19 @@ func handleField(
312294

313295
switch field {
314296
// TODO Add support for ECS fields
315-
case "srcaddr", "pkt-srcaddr", "dstaddr", "pkt-dstaddr":
297+
case "srcaddr":
298+
// handled later
299+
addr.source = value
300+
case "pkt-srcaddr":
301+
// handled later
302+
addr.pktSource = value
303+
case "dstaddr":
316304
// handled later
317-
ips[field] = value
305+
addr.destination = value
306+
case "pkt-dstaddr":
307+
// handled later
308+
addr.pktDestination = value
309+
318310
case "account-id":
319311
key.accountID = value
320312
case "vpc-id":

0 commit comments

Comments
 (0)