-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfeature.hpp
More file actions
161 lines (144 loc) · 5.91 KB
/
Copy pathfeature.hpp
File metadata and controls
161 lines (144 loc) · 5.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// 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 2025-Present Datadog, Inc.
#pragma once
#include <cinttypes>
#include <functional>
#include <memory>
#include <optional>
#include <string_view>
#include "datadog/impl/core/block.hpp"
#include "datadog/impl/core/context.hpp"
#include "datadog/impl/core/feature_id.hpp"
#include "datadog/impl/core/feature_message.hpp"
#include "datadog/impl/core/feature_scope.hpp"
#include "datadog/impl/core/http/body_writer.hpp"
#include "datadog/impl/core/tlv.hpp"
#include "datadog/impl/core/util/assert.hpp"
namespace datadog::impl {
class BatchReader;
class HttpRequestBuilder;
/**
* Lightweight description of an HTTP request that should be made in order to upload a
* batch of event data for a specific feature.
*/
struct Report {
/**
* Fully qualified URL (including query parameters if applicable) to use for the
* request. All requests are assumed to be POSTs. Underlying string data must persist
* throughout the lifetime of the HTTP request.
*/
const char* url;
/**
* The set of headers to use with this request, in wire format (e.g. 'Foo: bar'),
* CRLF-delimited, with a trailing CRLF.
*/
const char* headers;
/**
* A function that will populate the body of the HTTP request on demand, allowing
* large event payloads to be streamed directly to the HTTP layer without intermediate
* copies.
*/
HttpBodyWriter body_writer;
};
/**
* Describes how the storage thread should enforce size limits and other constraints on
* the batch files for a specific feature.
*/
struct FeatureStorageConfig {
// TODO: Implement defaults, use these values in BatchWriter
};
/**
* Base class used for the implementation of a feature. Implements user-facing API
* operations, generates event payloads for storage, and processes batches of those
* events for periodic upload.
*
* The Core is only aware of the Feature interface, and it keeps track of registered
* features via its own feature-agnostic data stucture, RegisteredFeature.
*
* To implement a new feature:
*
* - Establish a new source module `src/datadog/impl/features/foo`
* - In that module, define `class Foo final : public Feature { ... };`
* - Implement `GetId()` to return the globally unique FourCC code for that feature
* - Implement `GetName()` to return the globally unique name for logs, storage, etc.
* - If the feature has unique storage requirements, implement `GetStorageConfig()`
* - If the feature needs initialization/shutdown logic, implement `Start()`/`Stop()`
* - Define main-thread-callable functions for the required feature-specific operations
* - In those functions, call `_scope->ExecuteOnContextThread()` to generate events
* asynchronously on the context thread, using the provided `EventWriter`
* - Implement `UploadThread_PrepareReport()` to read batches of events (in the same
* format) and return a `Report` object describing the resulting HTTP request that
* should be made to upload that batch to the appropriate intake endpoint
*
* Additionally, for the user-facing operations that your new feature exposes:
*
* - Create `include-c/datadog/foo.h` and declare the feature's C API
* - Add `#include "datadog/foo.h"` to `include-c/datadog.h`
* - Create `src/datadog/c/foo.cpp` with bindings to the underlying implementation.
* - Create `include-cpp/datadog/foo.hpp` and declare the feature's C++ API
* - Add `#include "datadog/foo.hpp"` to `include-cpp/datadog.hpp`
* - Create `src/datadog/cpp/foo.cpp` with bindings to the underlying implementation.
*/
class Feature : public std::enable_shared_from_this<Feature> {
public:
Feature() = default;
virtual ~Feature() = default;
// Noncopyable, movable
Feature(const Feature&) = delete;
Feature& operator=(const Feature&) = delete;
Feature(Feature&&) = default;
Feature& operator=(Feature&&) = default;
virtual FeatureId GetId() const = 0;
virtual std::string_view GetName() const = 0;
virtual FeatureStorageConfig GetStorageConfig() const { return {}; }
void OnCoreStarted(FeatureScope&& feature_scope);
void OnCoreStopping();
protected:
/**
* Called from the main thread when the SDK has finished starting up. This is the
* first point at which _scope is valid.
*
* Once Start() is called, the feature may enqueue work on the context thread via
* _scope->ExecuteOnContextThread(), generating events in the process, until Stop() is
* called.
*/
virtual void Start() {}
/**
* Called from the main thread when the SDK is shutting down. This is the last point
* at which _scope is valid.
*
* Once Stop() is called, any work enqueued via _scope->ExecuteOnContextThread() will
* be ignored, and the feature may no longer generate events.
*/
virtual void Stop() {}
public:
/**
* Called from the upload thread when a batch of events written to storage by this
* feature is ready to be processed and uploaded.
*/
virtual std::optional<Report> UploadThread_PrepareReport(
BatchReader& reader, HttpRequestBuilder& builder
) = 0;
/**
* Called by `Core::Start()` each time the SDK starts up. If the feature wants to
* react to messages dispatched on the `MessageBus`, it should override this method
* and return a handler function: typically a lambda that captures `weak_from_this()`
* so that message delivery is silently skipped if the feature has already been
* destroyed.
*
* Implementations must be idempotent, as this function called on every `Start()`.
*
* The default implementation returns `std::nullopt`, meaning the feature opts out of
* message handling entirely.
*/
virtual std::optional<std::function<void(const FeatureMessage&)>>
MakeMessageHandler() {
return std::nullopt;
}
protected:
std::optional<FeatureScope> _scope;
};
} // namespace datadog::impl