-
Notifications
You must be signed in to change notification settings - Fork 134
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
RUMM-3151 feat: reduce number of view updates by filtering events fro…
…m payload
- Loading branch information
Showing
21 changed files
with
679 additions
and
155 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
/* | ||
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0. | ||
* This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
* Copyright 2019-Present Datadog, Inc. | ||
*/ | ||
|
||
import Foundation | ||
import DatadogInternal | ||
|
||
/// Event generator that generates events from the given data blocks. | ||
internal struct EventGenerator: Sequence, IteratorProtocol { | ||
private let dataBlocks: [DataBlock] | ||
private var index: Int | ||
|
||
init(dataBlocks: [DataBlock], index: Int = 0) { | ||
self.dataBlocks = dataBlocks | ||
self.index = index | ||
} | ||
|
||
/// Returns the next event. | ||
/// | ||
/// Data format | ||
/// ``` | ||
/// [EVENT 1 METADATA] [EVENT 1] [EVENT 2 METADATA] [EVENT 2] [EVENT 3] | ||
/// ``` | ||
/// | ||
/// - Returns: The next event or `nil` if there are no more events. | ||
/// - Note: a `DataBlock` with `.event` type marks the beginning of the event. | ||
/// It is either followed by another `DataBlock` with `.event` type or | ||
/// by a `DataBlock` with `.metadata` type. | ||
mutating func next() -> Event? { | ||
guard index < dataBlocks.count else { | ||
return nil | ||
} | ||
|
||
var metadata: DataBlock? = nil | ||
// If the next block is an event metadata, read it. | ||
if dataBlocks[index].type == .eventMetadata { | ||
metadata = dataBlocks[index] | ||
index += 1 | ||
} | ||
|
||
// If this is the last block, return nil. | ||
// there cannot be a metadata block without an event block. | ||
guard index < dataBlocks.count else { | ||
return nil | ||
} | ||
|
||
// If the next block is an event, read it. | ||
guard dataBlocks[index].type == .event else { | ||
// this is safeguard against corrupted data. | ||
// if there was a metadata block, it will be skipped. | ||
return next() | ||
} | ||
let event = dataBlocks[index] | ||
index += 1 | ||
|
||
return Event(data: event.data, metadata: metadata?.data) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ | |
*/ | ||
|
||
import Foundation | ||
import DatadogInternal | ||
|
||
internal struct Batch { | ||
/// Data blocks in the batch. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
/* | ||
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0. | ||
* This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
* Copyright 2019-Present Datadog, Inc. | ||
*/ | ||
|
||
import XCTest | ||
@testable import DatadogInternal | ||
|
||
final class DataFormatTests: XCTestCase { | ||
func testFormat() throws { | ||
let format = DataFormat(prefix: "prefix", suffix: "suffix", separator: "\n") | ||
let events = [ | ||
"abc".data(using: .utf8)!, | ||
"def".data(using: .utf8)!, | ||
"ghi".data(using: .utf8)! | ||
] | ||
let formatted = format.format(events) | ||
let actual = String(data: formatted, encoding: .utf8)! | ||
let expected = | ||
""" | ||
prefixabc | ||
def | ||
ghisuffix | ||
""" | ||
XCTAssertEqual(actual, expected) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/* | ||
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0. | ||
* This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
* Copyright 2019-2020 Datadog, Inc. | ||
*/ | ||
|
||
import Foundation | ||
import DatadogInternal | ||
|
||
internal struct RUMViewEventsFilter { | ||
let decoder: JSONDecoder | ||
|
||
init(decoder: JSONDecoder = JSONDecoder()) { | ||
self.decoder = decoder | ||
} | ||
|
||
func filter(events: [Event]) -> [Event] { | ||
var seen = Set<String>() | ||
var skipped: [String: [Int64]] = [:] | ||
|
||
// reversed is O(1) and no copy because it is view on the original array | ||
let filtered = events.reversed().compactMap { event in | ||
guard let metadata = event.metadata else { | ||
// If there is no metadata, we can't filter it. | ||
return event | ||
} | ||
|
||
guard let viewMetadata = try? decoder.decode(RUMViewEvent.Metadata.self, from: metadata) else { | ||
// If we can't decode the metadata, we can't filter it. | ||
return event | ||
} | ||
|
||
guard seen.contains(viewMetadata.id) == false else { | ||
// If we've already seen this view, we can skip this | ||
if skipped[viewMetadata.id] == nil { | ||
skipped[viewMetadata.id] = [] | ||
} | ||
skipped[viewMetadata.id]?.append(viewMetadata.documentVersion) | ||
return nil | ||
} | ||
|
||
seen.insert(viewMetadata.id) | ||
return event | ||
} | ||
|
||
for (id, versions) in skipped { | ||
DD.logger.debug("Skipping RUMViewEvent with id: \(id) and versions: \(versions.reversed().map(String.init).joined(separator: ", "))") | ||
} | ||
|
||
return filtered.reversed() | ||
} | ||
} |
Oops, something went wrong.