Skip to content

Commit 3facf4f

Browse files
committed
feat: Add C-bindings for hooks.
1 parent e99429d commit 3facf4f

17 files changed

Lines changed: 2003 additions & 0 deletions

libs/server-sdk/include/launchdarkly/server_side/bindings/c/config/builder.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include <launchdarkly/server_side/bindings/c/config/config.h>
77
#include <launchdarkly/server_side/bindings/c/config/lazy_load_builder/lazy_load_builder.h>
8+
#include <launchdarkly/server_side/bindings/c/hook.h>
89

910
#include <launchdarkly/bindings/c/config/logging_builder.h>
1011
#include <launchdarkly/bindings/c/export.h>
@@ -514,6 +515,25 @@ LD_EXPORT(void)
514515
LDServerConfigBuilder_Logging_Custom(LDServerConfigBuilder b,
515516
LDLoggingCustomBuilder custom_builder);
516517

518+
/**
519+
* Registers a hook with the SDK.
520+
*
521+
* Hooks allow you to instrument SDK behavior for logging, analytics,
522+
* or distributed tracing (e.g. OpenTelemetry).
523+
*
524+
* Multiple hooks can be registered. They execute in the order registered.
525+
*
526+
* LIFETIME: The hook struct is copied during this call. The Name string
527+
* must remain valid until LDServerConfigBuilder_Build() is called.
528+
* UserData and function pointers must remain valid for the SDK lifetime.
529+
*
530+
* @param builder Configuration builder. Must not be NULL.
531+
* @param hook Hook to register. The struct is copied. Must not be NULL.
532+
*/
533+
LD_EXPORT(void)
534+
LDServerConfigBuilder_Hooks(LDServerConfigBuilder builder,
535+
struct LDServerSDKHook hook);
536+
517537
/**
518538
* Creates an LDClientConfig. The builder is automatically freed.
519539
*
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/**
2+
* @file evaluation_series_context.h
3+
* @brief C bindings for read-only evaluation context passed to hooks.
4+
*
5+
* EvaluationSeriesContext provides information about a flag evaluation
6+
* to hook callbacks. All data is read-only and valid only during the
7+
* callback execution.
8+
*
9+
* LIFETIME:
10+
* - All context parameters are temporary - valid only during callback
11+
* - Do not store pointers to context data
12+
* - Copy any needed data (strings, values) if you need to retain it
13+
*/
14+
15+
#pragma once
16+
17+
#include <launchdarkly/bindings/c/export.h>
18+
#include <launchdarkly/server_side/bindings/c/hook_context.h>
19+
#include <launchdarkly/bindings/c/value.h>
20+
#include <launchdarkly/bindings/c/context.h>
21+
22+
// No effect in C++, but we want it for C.
23+
// ReSharper disable once CppUnusedIncludeDirective
24+
#include <stdbool.h> // NOLINT(*-deprecated-headers)
25+
26+
#ifdef __cplusplus
27+
extern "C" {
28+
#endif
29+
30+
typedef struct p_LDServerSDKEvaluationSeriesContext* LDServerSDKEvaluationSeriesContext;
31+
32+
/**
33+
* @brief Get the flag key being evaluated.
34+
*
35+
* @param eval_context Evaluation context. Must not be NULL.
36+
* @return Flag key as null-terminated UTF-8 string. Valid only during
37+
* the callback execution. Must not be freed.
38+
*/
39+
LD_EXPORT(char const*)
40+
LDEvaluationSeriesContext_FlagKey(LDServerSDKEvaluationSeriesContext eval_context);
41+
42+
/**
43+
* @brief Get the context (user/organization) being evaluated.
44+
*
45+
* @param eval_context Evaluation context. Must not be NULL.
46+
* @return Context object. Valid only during the callback execution.
47+
* Must not be freed. Do not call LDContext_Free() on this.
48+
*/
49+
LD_EXPORT(LDContext)
50+
LDEvaluationSeriesContext_Context(LDServerSDKEvaluationSeriesContext eval_context);
51+
52+
/**
53+
* @brief Get the default value provided to the variation call.
54+
*
55+
* @param eval_context Evaluation context. Must not be NULL.
56+
* @return Default value. Valid only during the callback execution.
57+
* Must not be freed. Do not call LDValue_Free() on this.
58+
*/
59+
LD_EXPORT(LDValue)
60+
LDEvaluationSeriesContext_DefaultValue(
61+
LDServerSDKEvaluationSeriesContext eval_context);
62+
63+
/**
64+
* @brief Get the name of the variation method called.
65+
*
66+
* Examples: "BoolVariation", "StringVariationDetail", "JsonVariation"
67+
*
68+
* @param eval_context Evaluation context. Must not be NULL.
69+
* @return Method name as null-terminated UTF-8 string. Valid only during
70+
* the callback execution. Must not be freed.
71+
*/
72+
LD_EXPORT(char const*)
73+
LDEvaluationSeriesContext_Method(LDServerSDKEvaluationSeriesContext eval_context);
74+
75+
/**
76+
* @brief Get the hook context provided by the caller.
77+
*
78+
* This contains application-specific data passed to the variation call,
79+
* such as OpenTelemetry span parents.
80+
*
81+
* @param eval_context Evaluation context. Must not be NULL.
82+
* @return Hook context. Valid only during the callback execution.
83+
* Must not be freed. Do not call LDHookContext_Free() on this.
84+
*/
85+
LD_EXPORT(LDHookContext)
86+
LDEvaluationSeriesContext_HookContext(
87+
LDServerSDKEvaluationSeriesContext eval_context);
88+
89+
/**
90+
* @brief Get the environment ID, if available.
91+
*
92+
* The environment ID is only available after SDK initialization completes.
93+
* Returns NULL if not yet available.
94+
*
95+
* @param eval_context Evaluation context. Must not be NULL.
96+
* @return Environment ID as null-terminated UTF-8 string, or NULL if not
97+
* available. Valid only during the callback execution. Must not
98+
* be freed.
99+
*/
100+
LD_EXPORT(char const*)
101+
LDEvaluationSeriesContext_EnvironmentId(
102+
LDServerSDKEvaluationSeriesContext eval_context);
103+
104+
#ifdef __cplusplus
105+
}
106+
#endif
Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
/**
2+
* @file evaluation_series_data.h
3+
* @brief C bindings for hook data passed between evaluation stages.
4+
*
5+
* EvaluationSeriesData is mutable data that hooks can use to pass information
6+
* from beforeEvaluation to afterEvaluation. This is useful for:
7+
* - Storing timing information
8+
* - Passing span contexts for distributed tracing
9+
* - Accumulating custom metrics
10+
*
11+
* LIFETIME AND OWNERSHIP:
12+
* - Data returned from hook callbacks transfers ownership to the SDK
13+
* - Data received in callbacks can be modified and returned (ownership transfer)
14+
* - Keys are copied by the SDK
15+
* - Values retrieved with GetValue() are heap-allocated copies that must be
16+
* freed by the caller using LDValue_Free()
17+
* - Values stored with SetValue() are copied into the data object
18+
* - Pointers (void*) lifetime is managed by the application
19+
*
20+
* BUILDER PATTERN:
21+
* To modify data, use LDEvaluationSeriesData_NewBuilder() to create a builder,
22+
* make changes, then build a new data object.
23+
*/
24+
25+
#pragma once
26+
27+
#include <launchdarkly/bindings/c/export.h>
28+
#include <launchdarkly/bindings/c/context.h>
29+
30+
// No effect in C++, but we want it for C.
31+
// ReSharper disable once CppUnusedIncludeDirective
32+
#include <stdbool.h> // NOLINT(*-deprecated-headers)
33+
// ReSharper disable once CppUnusedIncludeDirective
34+
#include <stddef.h> // NOLINT(*-deprecated-headers)
35+
36+
#ifdef __cplusplus
37+
extern "C" {
38+
#endif
39+
40+
typedef struct p_LDServerSDKEvaluationSeriesData* LDServerSDKEvaluationSeriesData;
41+
typedef struct p_LDEvaluationSeriesDataBuilder* LDServerSDKEvaluationSeriesDataBuilder;
42+
43+
44+
/**
45+
* @brief Create a new empty evaluation series data.
46+
*
47+
* @return New data object. Must be freed with LDEvaluationSeriesData_Free()
48+
* or transferred to SDK via hook callback return.
49+
*/
50+
LD_EXPORT(LDServerSDKEvaluationSeriesData)
51+
LDEvaluationSeriesData_New(void);
52+
53+
/**
54+
* @brief Get a Value from the evaluation series data.
55+
*
56+
* OWNERSHIP: Returns a heap-allocated copy of the value. The caller is
57+
* responsible for freeing it with LDValue_Free().
58+
*
59+
* USAGE:
60+
* @code
61+
* LDValue value;
62+
* if (LDEvaluationSeriesData_GetValue(data, "timestamp", &value)) {
63+
* // Use value
64+
* double timestamp = LDValue_GetNumber(value);
65+
* // Must free when done
66+
* LDValue_Free(value);
67+
* }
68+
* @endcode
69+
*
70+
* @param data Data object. Must not be NULL.
71+
* @param key Key to look up. Must be null-terminated UTF-8 string.
72+
* Must not be NULL.
73+
* @param out_value Pointer to receive the value. Must not be NULL.
74+
* Set to a heap-allocated LDValue that must be freed with
75+
* LDValue_Free() when no longer needed.
76+
* @return true if key was found and contains a Value, false otherwise.
77+
*/
78+
LD_EXPORT(bool)
79+
LDEvaluationSeriesData_GetValue(LDServerSDKEvaluationSeriesData data,
80+
char const* key,
81+
LDValue* out_value);
82+
83+
/**
84+
* @brief Get a pointer from the evaluation series data.
85+
*
86+
* Retrieves a pointer previously stored with
87+
* LDEvaluationSeriesDataBuilder_SetPointer().
88+
*
89+
* USAGE - OpenTelemetry span:
90+
* @code
91+
* void* span;
92+
* if (LDEvaluationSeriesData_GetPointer(data, "span", &span)) {
93+
* // Cast and use span
94+
* MySpan* typed_span = (MySpan*)span;
95+
* }
96+
* @endcode
97+
*
98+
* @param data Data object. Must not be NULL.
99+
* @param key Key to look up. Must be null-terminated UTF-8 string.
100+
* Must not be NULL.
101+
* @param out_pointer Pointer to receive the pointer value. Must not be NULL.
102+
* Set to NULL if key not found.
103+
* @return true if key was found and contains a pointer, false otherwise.
104+
*/
105+
LD_EXPORT(bool)
106+
LDEvaluationSeriesData_GetPointer(LDServerSDKEvaluationSeriesData data,
107+
char const* key,
108+
void** out_pointer);
109+
110+
/**
111+
* @brief Create a builder from existing data.
112+
*
113+
* Creates a builder initialized with the contents of the data object.
114+
* Use this to add or modify entries in the data.
115+
*
116+
* USAGE:
117+
* @code
118+
* LDServerSDKEvaluationSeriesDataBuilder builder =
119+
* LDEvaluationSeriesData_NewBuilder(input_data);
120+
* LDEvaluationSeriesDataBuilder_SetValue(builder, "key", value);
121+
* return LDEvaluationSeriesDataBuilder_Build(builder);
122+
* @endcode
123+
*
124+
* @param data Data to copy into builder. May be NULL (creates empty builder).
125+
* @return Builder object. Must be freed with
126+
* LDEvaluationSeriesDataBuilder_Free() or consumed with
127+
* LDEvaluationSeriesDataBuilder_Build().
128+
*/
129+
LD_EXPORT(LDServerSDKEvaluationSeriesDataBuilder)
130+
LDEvaluationSeriesData_NewBuilder(LDServerSDKEvaluationSeriesData data);
131+
132+
/**
133+
* @brief Free evaluation series data.
134+
*
135+
* Only call this if you created the data and are not returning it from
136+
* a hook callback. Data returned from callbacks is owned by the SDK.
137+
*
138+
* @param data Data to free. May be NULL (no-op).
139+
*/
140+
LD_EXPORT(void)
141+
LDEvaluationSeriesData_Free(LDServerSDKEvaluationSeriesData data);
142+
143+
/**
144+
* @brief Set a Value in the builder.
145+
*
146+
* OWNERSHIP: The value is copied/moved into the builder. You are responsible
147+
* for freeing the original value if needed.
148+
*
149+
* @param builder Builder object. Must not be NULL.
150+
* @param key Key for the value. Must be null-terminated UTF-8 string.
151+
* Must not be NULL. The key is copied.
152+
* @param value Value to store. Must not be NULL. The value is copied/moved.
153+
*/
154+
LD_EXPORT(void)
155+
LDEvaluationSeriesDataBuilder_SetValue(LDServerSDKEvaluationSeriesDataBuilder builder,
156+
char const* key,
157+
LDValue value);
158+
159+
/**
160+
* @brief Set a pointer in the builder.
161+
*
162+
* Stores an application-specific pointer. Useful for storing objects like
163+
* OpenTelemetry spans that need to be passed from beforeEvaluation to
164+
* afterEvaluation.
165+
*
166+
* LIFETIME: The pointer lifetime must extend through the evaluation series
167+
* (from beforeEvaluation through afterEvaluation).
168+
*
169+
* EXAMPLE - OpenTelemetry span:
170+
* @code
171+
* MySpan* span = start_span();
172+
* LDEvaluationSeriesDataBuilder_SetPointer(builder, "span", span);
173+
* @endcode
174+
*
175+
* @param builder Builder object. Must not be NULL.
176+
* @param key Key for the pointer. Must be null-terminated UTF-8 string.
177+
* Must not be NULL. The key is copied.
178+
* @param pointer Pointer to store. May be NULL. Lifetime managed by caller.
179+
*/
180+
LD_EXPORT(void)
181+
LDEvaluationSeriesDataBuilder_SetPointer(
182+
LDServerSDKEvaluationSeriesDataBuilder builder,
183+
char const* key,
184+
void* pointer);
185+
186+
/**
187+
* @brief Build the evaluation series data.
188+
*
189+
* Consumes the builder and creates a data object. After calling this,
190+
* do not call LDEvaluationSeriesDataBuilder_Free() on the builder.
191+
*
192+
* @param builder Builder to consume. Must not be NULL.
193+
* @return Data object. Must be freed with LDEvaluationSeriesData_Free()
194+
* or transferred to SDK via hook callback return.
195+
*/
196+
LD_EXPORT(LDServerSDKEvaluationSeriesData)
197+
LDEvaluationSeriesDataBuilder_Build(LDServerSDKEvaluationSeriesDataBuilder builder);
198+
199+
/**
200+
* @brief Free a builder without building.
201+
*
202+
* Only call this if you did not call LDEvaluationSeriesDataBuilder_Build().
203+
*
204+
* @param builder Builder to free. May be NULL (no-op).
205+
*/
206+
LD_EXPORT(void)
207+
LDEvaluationSeriesDataBuilder_Free(LDServerSDKEvaluationSeriesDataBuilder builder);
208+
209+
#ifdef __cplusplus
210+
}
211+
#endif

0 commit comments

Comments
 (0)