Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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