Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .github/actions/ci/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ inputs:
description: 'Whether to enable CURL networking (LD_CURL_NETWORKING=ON)'
required: false
default: 'false'
install_curl:
description: 'Whether to install CURL development libraries. Required for OpenTelemetry builds (server-sdk-otel), but does not enable CURL networking for the SDK itself.'
required: false
default: 'false'

runs:
using: composite
Expand All @@ -49,7 +53,7 @@ runs:
uses: ./.github/actions/install-openssl
id: install-openssl
- name: Install CURL
if: inputs.use_curl == 'true'
if: inputs.use_curl == 'true' || inputs.install_curl == 'true'
uses: ./.github/actions/install-curl
id: install-curl
- name: Build Library
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/manual-publish-doc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ on:
- libs/client-sdk
- libs/server-sdk
- libs/server-sdk-redis-source
- libs/server-sdk-otel
name: Publish Documentation
jobs:
build-publish:
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/release-please.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ jobs:
package-server-tag: ${{ steps.release.outputs['libs/server-sdk--tag_name'] }}
package-server-redis-released: ${{ steps.release.outputs['libs/server-sdk-redis-source--release_created'] }}
package-server-redis-tag: ${{ steps.release.outputs['libs/server-sdk-redis-source--tag_name'] }}
package-server-otel-released: ${{ steps.release.outputs['libs/server-sdk-otel--release_created'] }}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We aren't doing a build, so strictly speaking we don't need these, but I wonder if we should just leave them for consistency.

package-server-otel-tag: ${{ steps.release.outputs['libs/server-sdk-otel--tag_name'] }}
steps:
- uses: googleapis/release-please-action@v4
id: release
Expand Down Expand Up @@ -142,3 +144,4 @@ jobs:
upload-assets: true
upload-tag-name: ${{ needs.release-please.outputs.package-server-redis-tag }}
provenance-name: ${{ format('{0}-server-redis-multiple-provenance.intoto.jsonl', matrix.os) }}

54 changes: 54 additions & 0 deletions .github/workflows/server-otel.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: libs/server-sdk-otel

on:
push:
branches: [ main ]
paths-ignore:
- '**.md' # Do not need to run CI for markdown changes.
pull_request:
branches: [ "main", "feat/**" ]
paths-ignore:
- '**.md'
schedule:
# Run daily at midnight PST
- cron: '0 8 * * *'

jobs:
build-test-otel:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/ci
with:
cmake_target: launchdarkly-cpp-server-otel
install_curl: true
# We don't produce release artifacts.
simulate_release: false
build-otel-mac:
runs-on: macos-13
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/ci
with:
cmake_target: launchdarkly-cpp-server-otel
platform_version: 12
install_curl: true
# We don't produce release artifacts.
simulate_release: false
build-test-otel-windows:
runs-on: windows-2022
steps:
- uses: actions/checkout@v4
- uses: ilammy/msvc-dev-cmd@v1
- uses: ./.github/actions/ci
env:
BOOST_LIBRARY_DIR: 'C:\local\boost_1_87_0\lib64-msvc-14.3'
BOOST_LIBRARYDIR: 'C:\local\boost_1_87_0\lib64-msvc-14.3'
Boost_DIR: 'C:\local\boost_1_87_0\lib64-msvc-14.3\cmake\Boost-1.87.0'
with:
cmake_target: launchdarkly-cpp-server-otel
platform_version: 2022
toolset: msvc
install_curl: true
# We don't produce release artifacts.
simulate_windows_release: false
1 change: 1 addition & 0 deletions .release-please-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
"libs/internal": "0.12.1",
"libs/server-sdk": "3.9.1",
"libs/server-sdk-redis-source": "2.2.0",
"libs/server-sdk-otel": "0.0.0",
"libs/networking": "0.1.0"
}
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ option(LD_BUILD_EXAMPLES "Build hello-world examples." ON)

option(LD_BUILD_REDIS_SUPPORT "Build redis support." OFF)

option(LD_BUILD_OTEL_SUPPORT "Build OpenTelemetry integration." OFF)

option(LD_CURL_NETWORKING "Enable CURL-based networking for SSE client (alternative to Boost.Beast/Foxy)" OFF)

# If using 'make' as the build system, CMake causes the 'install' target to have a dependency on 'all', meaning
Expand Down Expand Up @@ -220,6 +222,11 @@ if (LD_BUILD_REDIS_SUPPORT)
add_subdirectory(libs/server-sdk-redis-source)
endif ()

if (LD_BUILD_OTEL_SUPPORT)
message("LaunchDarkly: building OpenTelemetry integration")
add_subdirectory(libs/server-sdk-otel)
endif ()

# Built as static or shared depending on LD_BUILD_SHARED_LIBS variable.
# This target "links" in common, internal, and sse as object libraries.
add_subdirectory(libs/client-sdk)
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ Various CMake options are available to customize the client/server SDK builds.
| `LD_DYNAMIC_LINK_OPENSSL` | Whether OpenSSL is dynamically linked or not. | Off (static link) | N/A |
| `LD_BUILD_REDIS_SUPPORT` | Whether the server-side Redis Source is built or not. | Off | N/A |
| `LD_CURL_NETWORKING` | Enable CURL-based networking for all HTTP requests (SSE streams and event delivery). When OFF, Boost.Beast/Foxy is used instead. CURL must be available as a dependency when this option is ON. | Off | N/A |
| `LD_BUILD_OTEL_SUPPORT` | Whether the server-side OpenTelemetry integration package is built or not. | Off | N/A |
| `LD_BUILD_OTEL_FETCH_DEPS` | When building OpenTelemetry support, automatically fetch and configure OpenTelemetry dependencies via CMake FetchContent. This is useful for local development and CI. When OFF, you must provide OpenTelemetry yourself via `find_package`. | Off | `LD_BUILD_OTEL_SUPPORT` |
| `LD_OTEL_CPP_VERSION` | Specifies the OpenTelemetry C++ SDK version (git tag or commit hash) to fetch when `LD_BUILD_OTEL_FETCH_DEPS` is enabled. Can be set to any valid git reference from the [opentelemetry-cpp repository](https://github.com/open-telemetry/opentelemetry-cpp). | `ea1f0d61ce5baa5584b097266bf133d1f31e3607` (v1.23.0) | `LD_BUILD_OTEL_FETCH_DEPS` |

> [!WARNING]
> When building shared libraries C++ symbols are not exported, only the C API will be exported. This is because C++ does
Expand Down
5 changes: 3 additions & 2 deletions cmake/json.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.24")
cmake_policy(SET CMP0135 NEW)
endif ()

FetchContent_Declare(json
# Use the same FetchContent name as OpenTelemetry to avoid duplicate targets
FetchContent_Declare(nlohmann_json
URL https://github.com/nlohmann/json/releases/download/v3.11.3/json.tar.xz
)

FetchContent_MakeAvailable(json)
FetchContent_MakeAvailable(nlohmann_json)
4 changes: 4 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@ if (LD_BUILD_REDIS_SUPPORT)
add_subdirectory(hello-cpp-server-redis)
add_subdirectory(hello-c-server-redis)
endif ()

if (LD_BUILD_OTEL_SUPPORT)
add_subdirectory(hello-cpp-server-otel)
endif ()
23 changes: 23 additions & 0 deletions examples/hello-cpp-server-otel/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Required for Apple Silicon support.
cmake_minimum_required(VERSION 3.19)

project(
LaunchDarklyHelloCPPServerOTel
VERSION 0.1
DESCRIPTION "LaunchDarkly Hello CPP Server-side SDK with OpenTelemetry Integration"
LANGUAGES CXX
)

set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)

add_executable(hello-cpp-server-otel main.cpp)

target_link_libraries(hello-cpp-server-otel
PRIVATE
launchdarkly::server
launchdarkly::server_otel
Threads::Threads
opentelemetry_trace
opentelemetry_exporter_otlp_http
)
85 changes: 85 additions & 0 deletions examples/hello-cpp-server-otel/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# LaunchDarkly C++ Server SDK - OpenTelemetry Integration Example

This example demonstrates how to integrate the LaunchDarkly C++ Server SDK with OpenTelemetry tracing to automatically enrich your distributed traces with feature flag evaluation data.

## What This Example Shows

- Setting up OpenTelemetry with OTLP HTTP exporter
- Configuring the LaunchDarkly OpenTelemetry tracing hook
- Creating HTTP spans with Boost.Beast
- Automatic feature flag span events in traces
- Passing explicit parent span context to evaluations

## Prerequisites

- C++17 or later
- CMake 3.19 or later
- Boost 1.81 or later
- LaunchDarkly SDK key

## Building

From the repository root:

```bash
mkdir build && cd build
cmake .. -DLD_BUILD_EXAMPLES=ON -DLD_BUILD_OTEL_SUPPORT=ON
cmake --build . --target hello-cpp-server-otel
```

## Running

### 1. Set Your LaunchDarkly SDK Key

Either edit `main.cpp` and set the `SDK_KEY` constant, or use an environment variable:

```bash
export LD_SDK_KEY=your-sdk-key-here
```

### 2. Create a Feature Flag

In your LaunchDarkly dashboard, create a boolean flag named `show-detailed-weather`.

### 3. Run the Example

```bash
./build/examples/hello-cpp-server-otel/hello-cpp-server-otel
```

You should see:

```
*** SDK successfully initialized!

*** Weather server running on http://0.0.0.0:8080
*** Try: curl http://localhost:8080/weather
*** OpenTelemetry tracing enabled, sending traces to LaunchDarkly
*** LaunchDarkly integration enabled with OpenTelemetry tracing hook
```

### 4. Make Requests

```bash
curl http://localhost:8080/weather
```

### 5. View Traces in LaunchDarkly

Navigate to your LaunchDarkly project's Observability section to view traces. Each HTTP request will have:
1. **Root Span**: "HTTP GET /weather" with HTTP attributes
2. **Feature Flag Event**: Attached to the span with evaluation details:
- `feature_flag.key`: "show-detailed-weather"
- `feature_flag.provider.name`: "LaunchDarkly"
- `feature_flag.context.id`: "user:weather-api-user"
- `feature_flag.result.value`: The evaluated flag value


### Custom OTLP Endpoint

To send traces to a different OpenTelemetry collector, set the `LD_OTEL_ENDPOINT` environment variable:

```bash
export LD_OTEL_ENDPOINT=http://localhost:4318/v1/traces
./build/examples/hello-cpp-server-otel/hello-cpp-server-otel
```
Loading
Loading