diff --git a/instrumentation/otel-webserver-module/README.md b/instrumentation/otel-webserver-module/README.md index 5ebdeea95..d3f0d0e33 100644 --- a/instrumentation/otel-webserver-module/README.md +++ b/instrumentation/otel-webserver-module/README.md @@ -59,6 +59,7 @@ Monitoring individual modules is crucial to the instrumentation of Apache web se |*ApacheModuleSegmentType* | | OPTIONAL: Specify the string (FIRST/LAST/CUSTOM) to be filtered for Span Name Creation| |*ApacheModuleSegmentParameter* | | OPTIONAL: Specify the segment count or segment numbers that you want to display for Span Creation| |*ApacheModuleOtelExporterHeaders* | | OPTIONAL: OTEL Exporter header info or Metadata like API key for OTLP endpoint. a list of key value pairs, and these are expected to be represented in a format matching to the W3C Correlation-Context, except that additional semi-colon delimited metadata is not supported, i.e.: key1=value1,key2=value2. | +|*ApacheModuleOtelExporterOtlpProtocol* | http/protobuf | OPTIONAL: OTLP export protocol. Supported values are "grpc", "http/protobuf", and "http/json". Can also be set via OTEL_EXPORTER_OTLP_TRACES_PROTOCOL or OTEL_EXPORTER_OTLP_PROTOCOL environment variables. | A sample configuration is mentioned in [opentelemetry_module.conf](https://github.com/open-telemetry/opentelemetry-cpp-contrib/blob/main/instrumentation/otel-webserver-module/opentelemetry_module.conf) @@ -176,6 +177,7 @@ Currently, Nginx Webserver module monitores some fixed set of modules, which get |*NginxModuleRequestHeaders* | | OPTIONAL: Specify the request headers to be captured in the span attributes. The headers are Case-Sensitive and should be comma-separated. e.g.```NginxModuleRequestHeaders Accept-Charset,Accept-Encoding,User-Agent;```| |*NginxModuleResponseHeaders* | | OPTIONAL: Specify the response headers to be captured in the span attributes. The headers are Case-Sensitive and should be comma-separated. e.g.```NginxModuleResponseHeaders Content-Length,Content-Type;```| |*NginxModuleOtelExporterOtlpHeaders* | | OPTIONAL: OTEL exporter headers like Meta data related exposrted end point. a list of key value pairs, and these are expected to be represented in a format matching to the W3C Correlation-Context, except that additional semi-colon delimited metadata is not supported, i.e.: key1=value1,key2=value2.| +|*NginxModuleOtelExporterOtlpProtocol* | http/protobuf | OPTIONAL: OTLP export protocol. Supported values are "grpc", "http/protobuf", and "http/json". Can also be set via OTEL_EXPORTER_OTLP_TRACES_PROTOCOL or OTEL_EXPORTER_OTLP_PROTOCOL environment variables.| |*NginxModuleTrustIncomingSpans* | ON | OPTIONAL: Specify if you want to correlate Nginx instrumented traces and spans with incoming requests.| |*NginxModuleAttributes* | | OPTIONAL: Can be used to pass additionalccustom attributes to the span, nginx variables are also supported. All elements must be separated by a space, and different attribute key value pairs must be separated by a comma( even the comma needs to be separated by space). e.g. ```NginxModuleAttributes Key1 Value1 , Key2 $request_uri;``` | |*NginxModuleIgnorePaths* | | OPTIONAL: Request URIs matching the Regex will not be monitored. Multiple space separated Regex can be provided( `'\'` symbol needs to be used carefully, Nginx treats `'\'` as a escape sequence, thus if the Regex sequence contains a `'\'`, it need to be replaced by `'\\'`, likewise if sequence contains `'\\'`, it need to be written as `'\\\\'` e.g. `.*\.html` -> `.*\\.html` ) e.g. ```NginxModuleIgnorePaths .*\\.html /test_.*;```| diff --git a/instrumentation/otel-webserver-module/build.gradle b/instrumentation/otel-webserver-module/build.gradle index 5f8ea4a41..154fa2977 100644 --- a/instrumentation/otel-webserver-module/build.gradle +++ b/instrumentation/otel-webserver-module/build.gradle @@ -189,6 +189,8 @@ task stageLibrary(type: Copy) { from("${modDepDir}/opentelemetry/${cppSDKVersion}/lib/libopentelemetry_otlp_recordable.so") { it.into "sdk_lib/lib" } from("${modDepDir}/opentelemetry/${cppSDKVersion}/lib/libopentelemetry_exporter_ostream_span.so") { it.into "sdk_lib/lib" } from("${modDepDir}/opentelemetry/${cppSDKVersion}/lib/libopentelemetry_exporter_otlp_grpc.so") { it.into "sdk_lib/lib" } + from("${modDepDir}/opentelemetry/${cppSDKVersion}/lib/libopentelemetry_exporter_otlp_http.so") { it.into "sdk_lib/lib" } + from("${modDepDir}/opentelemetry/${cppSDKVersion}/lib/libopentelemetry_http_client_curl.so") { it.into "sdk_lib/lib" } from("dist/opentelemetry_sdk_log4cxx.xml.template") { it.into "conf" } from("dist/install.${scriptExt}") { it.fileMode 0700 } diff --git a/instrumentation/otel-webserver-module/conf/nginx/opentelemetry_module.conf b/instrumentation/otel-webserver-module/conf/nginx/opentelemetry_module.conf index e3eb6ed2d..c028ae4b0 100644 --- a/instrumentation/otel-webserver-module/conf/nginx/opentelemetry_module.conf +++ b/instrumentation/otel-webserver-module/conf/nginx/opentelemetry_module.conf @@ -2,6 +2,7 @@ NginxModuleEnabled ON; #NginxModule Otel Exporter details NginxModuleOtelSpanExporter otlp; NginxModuleOtelExporterEndpoint docker.for.mac.localhost:4317; +#NginxModuleOtelExporterOtlpProtocol http/protobuf; #NginxModuleOtelExporterOtlpHeaders Authorization=AuthorizationToken; # SSL Certificates #NginxModuleOtelSslEnabled ON diff --git a/instrumentation/otel-webserver-module/include/apache/ApacheConfig.h b/instrumentation/otel-webserver-module/include/apache/ApacheConfig.h index ebef128e4..615740485 100644 --- a/instrumentation/otel-webserver-module/include/apache/ApacheConfig.h +++ b/instrumentation/otel-webserver-module/include/apache/ApacheConfig.h @@ -42,6 +42,9 @@ class otel_cfg const char* getOtelExporterOtlpHeaders() { return otelExporterOtlpHeaders; } int otelExporterOtlpHeadersInitialized() { return otelExporterOtlpHeaders_initialized; } + const char* getOtelExporterOtlpProtocol() { return otelExporterOtlpProtocol; } + int otelExporterOtlpProtocolInitialized() { return otelExporterOtlpProtocol_initialized; } + int getOtelSslEnabled() { return otelSslEnabled; } int getOtelSslEnabledInitialized() { return otelSslEnabled_initialized; } @@ -129,6 +132,9 @@ class otel_cfg const char *otelExporterOtlpHeaders; // OPTIONAL: AppDynamics Custom metadata for OTEL Exporter EX: OTEL_EXPORTER_OTLP_HEADERS="api-key=key,other-config-value=value" int otelExporterOtlpHeaders_initialized; + const char *otelExporterOtlpProtocol; // OPTIONAL: OTLP export protocol: grpc, http/protobuf, http/json (default: http/protobuf) + int otelExporterOtlpProtocol_initialized; + int otelSslEnabled; // OPTIONAL: Decision whether connection to the Exporter endpoint is secured int otelSslEnabled_initialized; @@ -231,6 +237,7 @@ class ApacheConfigHandlers static const char* otel_set_otelExporterType(cmd_parms *cmd, void *conf, const char *arg); static const char* otel_set_otelExporterEndpoint(cmd_parms *cmd, void *conf, const char *arg); static const char* otel_set_otelExporterOtlpHeaders(cmd_parms *cmd, void *conf, const char *arg); + static const char* otel_set_otelExporterOtlpProtocol(cmd_parms *cmd, void *conf, const char *arg); static const char* otel_set_otelSslEnabled(cmd_parms *cmd, void *conf, const char *arg); static const char* otel_set_otelSslCertificatePath(cmd_parms *cmd, void *conf, const char *arg); static const char* otel_set_otelProcessorType(cmd_parms *cmd, void *conf, const char *arg); diff --git a/instrumentation/otel-webserver-module/include/apache/ApacheHooks.h b/instrumentation/otel-webserver-module/include/apache/ApacheHooks.h index 0b3f13198..a00ecef65 100644 --- a/instrumentation/otel-webserver-module/include/apache/ApacheHooks.h +++ b/instrumentation/otel-webserver-module/include/apache/ApacheHooks.h @@ -33,7 +33,7 @@ class ApacheHooks static const char* OTEL_INTERACTION_HANDLE_KEY; static const char* OTEL_REQ_HANDLE_KEY; static const int LOWEST_HTTP_ERROR_CODE = 400; - static const int CONFIG_COUNT = 17; // Number of key value pairs in config + static const int CONFIG_COUNT = 18; // Number of key value pairs in config static const std::initializer_list httpHeaders; static void registerHooks(apr_pool_t *p); diff --git a/instrumentation/otel-webserver-module/include/core/api/OpentelemetrySdk.h b/instrumentation/otel-webserver-module/include/core/api/OpentelemetrySdk.h index 4c400fb3d..af8266167 100755 --- a/instrumentation/otel-webserver-module/include/core/api/OpentelemetrySdk.h +++ b/instrumentation/otel-webserver-module/include/core/api/OpentelemetrySdk.h @@ -28,6 +28,7 @@ #define OTEL_SDK_ENV_OTEL_EXPORTER_TYPE "OTEL_SDK_ENV_OTEL_EXPORTER_TYPE" #define OTEL_SDK_ENV_OTEL_EXPORTER_ENDPOINT "OTEL_SDK_ENV_OTEL_EXPORTER_ENDPOINT" /*required*/ #define OTEL_SDK_ENV_OTEL_EXPORTER_OTLPHEADERS "OTEL_SDK_ENV_OTEL_EXPORTER_OTLPHEADERS" /*optional*/ +#define OTEL_SDK_ENV_OTEL_EXPORTER_OTLP_PROTOCOL "OTEL_SDK_ENV_OTEL_EXPORTER_OTLP_PROTOCOL" /*optional: grpc, http/protobuf, http/json*/ #define OTEL_SDK_ENV_OTEL_SSL_ENABLED "OTEL_SDK_ENV_OTEL_SSL_ENABLED" /*optional*/ #define OTEL_SDK_ENV_OTEL_SSL_CERTIFICATE_PATH "OTEL_SDK_ENV_OTEL_SSL_CERTIFICATE_PATH" /*optional*/ #define OTEL_SDK_ENV_OTEL_PROCESSOR_TYPE "OTEL_SDK_ENV_OTEL_PROCESSOR_TYPE" diff --git a/instrumentation/otel-webserver-module/include/core/api/TenantConfig.h b/instrumentation/otel-webserver-module/include/core/api/TenantConfig.h index d29c6e7c4..9440c9e0b 100644 --- a/instrumentation/otel-webserver-module/include/core/api/TenantConfig.h +++ b/instrumentation/otel-webserver-module/include/core/api/TenantConfig.h @@ -46,6 +46,7 @@ class TenantConfig const std::string& getOtelExporterType() const {return otelExporterType;} const std::string& getOtelExporterEndpoint() const {return otelExporterEndpoint;} const std::string& getOtelExporterOtlpHeaders() const {return otelExporterOtlpHeaders;} + const std::string& getOtelExporterOtlpProtocol() const {return otelExporterOtlpProtocol;} const std::string& getOtelProcessorType() const {return otelProcessorType;} const std::string& getOtelPropagatorType() const {return otelPropagatorType;} const unsigned getOtelMaxQueueSize() const {return otelMaxQueueSize;} @@ -64,6 +65,7 @@ class TenantConfig void setOtelExporterType(const std::string& otelExporterType) { this->otelExporterType = otelExporterType; } void setOtelExporterEndpoint(const std::string& otelExporterEndpoint) { this->otelExporterEndpoint = otelExporterEndpoint; } void setOtelExporterOtlpHeaders(const std::string& otelExporterOtlpHeaders) { this->otelExporterOtlpHeaders = otelExporterOtlpHeaders; } + void setOtelExporterOtlpProtocol(const std::string& otelExporterOtlpProtocol) { this->otelExporterOtlpProtocol = otelExporterOtlpProtocol; } void setOtelProcessorType(const std::string& otelProcessorType) { this->otelProcessorType = otelProcessorType; } void setOtelPropagatorType(const std::string& otelPropagatorType) { this->otelPropagatorType = otelPropagatorType; } void setOtelMaxQueueSize(const unsigned int otelMaxQueueSize) { this->otelMaxQueueSize = otelMaxQueueSize; } @@ -85,6 +87,7 @@ class TenantConfig std::string otelExporterType; std::string otelExporterEndpoint; std::string otelExporterOtlpHeaders; + std::string otelExporterOtlpProtocol; bool otelSslEnabled; std::string otelSslCertPath; std::string otelPropagatorType; @@ -110,6 +113,7 @@ inline std::ostream& operator<< (std::ostream &os, const otel::core::TenantConfi << "\n OtelLibraryVersion " << config.getOtelLibraryVersion() << "\n OtelExporterType " << config.getOtelExporterType() << "\n OtelExporterEndpoint " << config.getOtelExporterEndpoint() + << "\n OtelExporterOtlpProtocol " << config.getOtelExporterOtlpProtocol() << "\n OtelProcessorType " << config.getOtelProcessorType() << "\n OtelPropagatorType " << config.getOtelPropagatorType() << "\n OtelSamplerType " << config.getOtelSamplerType() diff --git a/instrumentation/otel-webserver-module/opentelemetry_module.conf b/instrumentation/otel-webserver-module/opentelemetry_module.conf index b5b0a9194..b151044ab 100755 --- a/instrumentation/otel-webserver-module/opentelemetry_module.conf +++ b/instrumentation/otel-webserver-module/opentelemetry_module.conf @@ -4,6 +4,8 @@ LoadFile /opt/opentelemetry-webserver-sdk/sdk_lib/lib/libopentelemetry_trace.so LoadFile /opt/opentelemetry-webserver-sdk/sdk_lib/lib/libopentelemetry_otlp_recordable.so LoadFile /opt/opentelemetry-webserver-sdk/sdk_lib/lib/libopentelemetry_exporter_ostream_span.so LoadFile /opt/opentelemetry-webserver-sdk/sdk_lib/lib/libopentelemetry_exporter_otlp_grpc.so +LoadFile /opt/opentelemetry-webserver-sdk/sdk_lib/lib/libopentelemetry_exporter_otlp_http.so +LoadFile /opt/opentelemetry-webserver-sdk/sdk_lib/lib/libopentelemetry_http_client_curl.so #Load the ApacheModule SDK LoadFile /opt/opentelemetry-webserver-sdk/sdk_lib/lib/libopentelemetry_webserver_sdk.so @@ -14,6 +16,7 @@ ApacheModuleEnabled ON #ApacheModule Otel Exporter details ApacheModuleOtelSpanExporter otlp ApacheModuleOtelExporterEndpoint collector:4317 +#ApacheModuleOtelExporterOtlpProtocol http/protobuf #ApacheModuleOtelExporterHeaders api-key=abc123 # SSL Certificates diff --git a/instrumentation/otel-webserver-module/src/apache/ApacheConfig.cpp b/instrumentation/otel-webserver-module/src/apache/ApacheConfig.cpp index 92c59e875..cbd787952 100644 --- a/instrumentation/otel-webserver-module/src/apache/ApacheConfig.cpp +++ b/instrumentation/otel-webserver-module/src/apache/ApacheConfig.cpp @@ -129,6 +129,14 @@ const char* ApacheConfigHandlers::otel_set_otelExporterOtlpHeaders(cmd_parms *cm return helperChar(cmd, cfg, arg, cfg->otelExporterOtlpHeaders, cfg->otelExporterOtlpHeaders_initialized, "otel_set_otelExporterOtlpHeaders"); } +// char *otelExporterOtlpProtocol; +// int otelExporterOtlpProtocol_initialized; +const char* ApacheConfigHandlers::otel_set_otelExporterOtlpProtocol(cmd_parms *cmd, void *conf, const char *arg) +{ + otel_cfg* cfg = (otel_cfg*) conf; + return helperChar(cmd, cfg, arg, cfg->otelExporterOtlpProtocol, cfg->otelExporterOtlpProtocol_initialized, "otel_set_otelExporterOtlpProtocol"); +} + // char *otelSslEnabled; // int otelSslEnabled_initialized; const char* ApacheConfigHandlers::otel_set_otelSslEnabled(cmd_parms *cmd, void *conf, const char *arg) @@ -444,6 +452,10 @@ void otel_cfg::init() otelExporterOtlpHeaders = ""; otelExporterOtlpHeaders_initialized = 0; + // otelExporterOtlpProtocol Optional: OTLP export protocol: grpc, http/protobuf, http/json + otelExporterOtlpProtocol = ""; + otelExporterOtlpProtocol_initialized = 0; + // otelSslEnabled OPTIONAL: Decides whether the connection to the endpoint is secured otelSslEnabled = 0; otelSslEnabled_initialized = 0; @@ -657,6 +669,11 @@ void* ApacheConfigHandlers::otel_merge_dir_config(apr_pool_t* p, void* parent_co apr_pstrdup(p, nconf->otelSslCertificatePath) : apr_pstrdup(p, pconf->otelSslCertificatePath); merged_config->otelSslCertificatePath_initialized = 1; + // otelExporterOtlpProtocol OPTIONAL: OTLP export protocol: grpc, http/protobuf, http/json + merged_config->otelExporterOtlpProtocol = nconf->otelExporterOtlpProtocol_initialized ? + apr_pstrdup(p, nconf->otelExporterOtlpProtocol) : apr_pstrdup(p, pconf->otelExporterOtlpProtocol); + merged_config->otelExporterOtlpProtocol_initialized = 1; + // otelExporterType OPTIONAL: Type of exporter to be configured in TracerProvider of OTel SDK embedded into Agent merged_config->otelExporterType = nconf->otelExporterType_initialized ? apr_pstrdup(p, nconf->otelExporterType) : apr_pstrdup(p, pconf->otelExporterType); @@ -786,6 +803,9 @@ otel_cfg* ApacheConfigHandlers::getProcessConfig(const request_rec* r) process_cfg->otelExporterOtlpHeaders = apr_pstrdup(r->server->process->pool, our_config->otelExporterOtlpHeaders); process_cfg->otelExporterOtlpHeaders_initialized = our_config->otelExporterOtlpHeaders_initialized; + process_cfg->otelExporterOtlpProtocol = apr_pstrdup(r->server->process->pool, our_config->otelExporterOtlpProtocol); + process_cfg->otelExporterOtlpProtocol_initialized = our_config->otelExporterOtlpProtocol_initialized; + process_cfg->otelSslEnabled = our_config->otelSslEnabled; process_cfg->otelSslEnabled_initialized = our_config->otelSslEnabled_initialized; diff --git a/instrumentation/otel-webserver-module/src/apache/ApacheHooks.cpp b/instrumentation/otel-webserver-module/src/apache/ApacheHooks.cpp index 1bb575575..5d67e6aed 100644 --- a/instrumentation/otel-webserver-module/src/apache/ApacheHooks.cpp +++ b/instrumentation/otel-webserver-module/src/apache/ApacheHooks.cpp @@ -426,11 +426,16 @@ bool ApacheHooks::initialize_opentelemetry(const request_rec *r) env_config[ix].value = our_config->getSegmentParameter(); ++ix; - // Segment Parameter + // OTLP Headers env_config[ix].name = OTEL_SDK_ENV_OTEL_EXPORTER_OTLPHEADERS; env_config[ix].value = our_config->getOtelExporterOtlpHeaders(); ++ix; + // OTLP Protocol + env_config[ix].name = OTEL_SDK_ENV_OTEL_EXPORTER_OTLP_PROTOCOL; + env_config[ix].value = our_config->getOtelExporterOtlpProtocol(); + ++ix; + // !!! // Remember to update the apr_pcalloc call size if we add another parameter to the input array! // !!! diff --git a/instrumentation/otel-webserver-module/src/apache/mod_apache_otel.cpp b/instrumentation/otel-webserver-module/src/apache/mod_apache_otel.cpp index f01fdd550..c53aa6baa 100644 --- a/instrumentation/otel-webserver-module/src/apache/mod_apache_otel.cpp +++ b/instrumentation/otel-webserver-module/src/apache/mod_apache_otel.cpp @@ -70,6 +70,12 @@ static const command_rec otel_cmds[] = NULL, OR_ALL, "AppDynamics Otel export Headers key value pairs"), + AP_INIT_TAKE1( + "apacheModuleOtelExporterOtlpProtocol", + (CMD_HAND_TYPE)ApacheConfigHandlers::otel_set_otelExporterOtlpProtocol, + NULL, + OR_ALL, + "OTLP export protocol: grpc, http/protobuf, or http/json (default: http/protobuf)"), AP_INIT_TAKE1( "apacheModuleOtelSslEnabled", (CMD_HAND_TYPE)ApacheConfigHandlers::otel_set_otelSslEnabled, diff --git a/instrumentation/otel-webserver-module/src/build.gyp b/instrumentation/otel-webserver-module/src/build.gyp index 07f8a1eb2..1ba5aaa55 100644 --- a/instrumentation/otel-webserver-module/src/build.gyp +++ b/instrumentation/otel-webserver-module/src/build.gyp @@ -55,6 +55,8 @@ '$(ANSDK_DIR)/opentelemetry/$(CPP_SDK_VERSION)/lib/libopentelemetry_otlp_recordable.so', '$(ANSDK_DIR)/opentelemetry/$(CPP_SDK_VERSION)/lib/libopentelemetry_exporter_ostream_span.so', '$(ANSDK_DIR)/opentelemetry/$(CPP_SDK_VERSION)/lib/libopentelemetry_exporter_otlp_grpc.so', + '$(ANSDK_DIR)/opentelemetry/$(CPP_SDK_VERSION)/lib/libopentelemetry_exporter_otlp_http.so', + '$(ANSDK_DIR)/opentelemetry/$(CPP_SDK_VERSION)/lib/libopentelemetry_http_client_curl.so', '$(BOOST_LIB)', '$(LINKER_FLAGS)', '$(LIBRARY_FLAGS)', diff --git a/instrumentation/otel-webserver-module/src/core/api/ApiUtils.cpp b/instrumentation/otel-webserver-module/src/core/api/ApiUtils.cpp index 72f9f1271..54b3bd84f 100755 --- a/instrumentation/otel-webserver-module/src/core/api/ApiUtils.cpp +++ b/instrumentation/otel-webserver-module/src/core/api/ApiUtils.cpp @@ -168,6 +168,7 @@ OTEL_SDK_STATUS_CODE ApiUtils::ReadSettingsFromReader( std::string otelExporterType; std::string otelExporterEndpoint; std::string otelExporterOtlpHeaders; + std::string otelExporterOtlpProtocol; bool otelSslEnabled; std::string otelSslCertPath; std::string otelLibraryName; @@ -263,6 +264,19 @@ OTEL_SDK_STATUS_CODE ApiUtils::ReadSettingsFromReader( reader.ReadOptional( std::string(OTEL_SDK_ENV_OTEL_EXPORTER_OTLPHEADERS), otelExporterOtlpHeaders); + reader.ReadOptional( + std::string(OTEL_SDK_ENV_OTEL_EXPORTER_OTLP_PROTOCOL), otelExporterOtlpProtocol); + + // Fall back to standard OTel environment variable if not set via module config + if (otelExporterOtlpProtocol.empty()) { + char* envProtocol = getenv("OTEL_EXPORTER_OTLP_TRACES_PROTOCOL"); + if (!envProtocol) { + envProtocol = getenv("OTEL_EXPORTER_OTLP_PROTOCOL"); + } + if (envProtocol) { + otelExporterOtlpProtocol = envProtocol; + } + } tenantConfig.setServiceNamespace(serviceNamespace); tenantConfig.setServiceName(serviceName); @@ -270,6 +284,7 @@ OTEL_SDK_STATUS_CODE ApiUtils::ReadSettingsFromReader( tenantConfig.setOtelExporterType(otelExporterType); tenantConfig.setOtelExporterEndpoint(otelExporterEndpoint); tenantConfig.setOtelExporterOtlpHeaders(otelExporterOtlpHeaders); + tenantConfig.setOtelExporterOtlpProtocol(otelExporterOtlpProtocol); tenantConfig.setOtelLibraryName(otelLibraryName); tenantConfig.setOtelProcessorType(otelProcessorType); tenantConfig.setOtelPropagatorType(otelPropagatorType); diff --git a/instrumentation/otel-webserver-module/src/core/sdkwrapper/SdkHelperFactory.cpp b/instrumentation/otel-webserver-module/src/core/sdkwrapper/SdkHelperFactory.cpp index 40ab24886..fa56d7b59 100644 --- a/instrumentation/otel-webserver-module/src/core/sdkwrapper/SdkHelperFactory.cpp +++ b/instrumentation/otel-webserver-module/src/core/sdkwrapper/SdkHelperFactory.cpp @@ -26,6 +26,7 @@ #include "opentelemetry/sdk/trace/samplers/trace_id_ratio.h" #include "opentelemetry/sdk/resource/resource.h" #include "opentelemetry/exporters/otlp/otlp_grpc_exporter.h" +#include "opentelemetry/exporters/otlp/otlp_http_exporter.h" #include "opentelemetry/exporters/otlp/otlp_environment.h" #include "opentelemetry/baggage/propagation/baggage_propagator.h" #include @@ -48,6 +49,9 @@ namespace { constexpr const char* PARENT_BASED_SAMPLER = "parent"; constexpr const char* TRACE_ID_RATIO_BASED_SAMPLER = "trace_id_ratio"; constexpr const char* PROPAGATOR_TYPE_B3 = "b3"; + constexpr const char* PROTOCOL_GRPC = "grpc"; + constexpr const char* PROTOCOL_HTTP_PROTOBUF = "http/protobuf"; + constexpr const char* PROTOCOL_HTTP_JSON = "http/json"; } SdkHelperFactory::SdkHelperFactory( @@ -132,45 +136,99 @@ OtelSpanExporter SdkHelperFactory::GetExporter( exporter.reset(new opentelemetry::exporter::trace::OStreamSpanExporter); } else { if (type != OTLP_EXPORTER_TYPE) { - // default is otlp exporter LOG4CXX_WARN(mLogger, "Received unknown exporter type: " << type << ". Will create default(otlp) exporter"); type = OTLP_EXPORTER_TYPE; } - opentelemetry::exporter::otlp::OtlpGrpcExporterOptions opts; - opts.endpoint = config->getOtelExporterEndpoint(); - if (config->getOtelSslEnabled()) { - opts.use_ssl_credentials = config->getOtelSslEnabled(); - opts.ssl_credentials_cacert_path = config->getOtelSslCertPath(); - LOG4CXX_TRACE(mLogger, "Ssl Credentials are enabled for exporter, path: " - << opts.ssl_credentials_cacert_path); + + auto protocol = config->getOtelExporterOtlpProtocol(); + if (protocol.empty()) { + protocol = PROTOCOL_HTTP_PROTOBUF; } - opentelemetry::common::KeyValueStringTokenizer tokenizer{config->getOtelExporterOtlpHeaders()}; - opentelemetry::nostd::string_view header_key; - opentelemetry::nostd::string_view header_value; - bool header_valid = true; - std::unordered_set remove_cache; + LOG4CXX_INFO(mLogger, "OTLP exporter protocol: " << protocol); + + if (protocol == PROTOCOL_GRPC) { + opentelemetry::exporter::otlp::OtlpGrpcExporterOptions opts; + opts.endpoint = config->getOtelExporterEndpoint(); + if (config->getOtelSslEnabled()) { + opts.use_ssl_credentials = config->getOtelSslEnabled(); + opts.ssl_credentials_cacert_path = config->getOtelSslCertPath(); + LOG4CXX_TRACE(mLogger, "Ssl Credentials are enabled for exporter, path: " + << opts.ssl_credentials_cacert_path); + } + + opentelemetry::common::KeyValueStringTokenizer tokenizer{config->getOtelExporterOtlpHeaders()}; + opentelemetry::nostd::string_view header_key; + opentelemetry::nostd::string_view header_value; + bool header_valid = true; + std::unordered_set remove_cache; - while (tokenizer.next(header_valid, header_key, header_value)) - { - if (header_valid) + while (tokenizer.next(header_valid, header_key, header_value)) { - std::string key = static_cast(header_key); - if (remove_cache.end() == remove_cache.find(key)) + if (header_valid) { - remove_cache.insert(key); - auto range = opts.metadata.equal_range(key); - if (range.first != range.second) + std::string key = static_cast(header_key); + if (remove_cache.end() == remove_cache.find(key)) { - opts.metadata.erase(range.first, range.second); + remove_cache.insert(key); + auto range = opts.metadata.equal_range(key); + if (range.first != range.second) + { + opts.metadata.erase(range.first, range.second); + } } + + opts.metadata.emplace(std::make_pair(std::move(key), static_cast(header_value))); } + } - opts.metadata.emplace(std::make_pair(std::move(key), static_cast(header_value))); + exporter.reset(new opentelemetry::exporter::otlp::OtlpGrpcExporter(opts)); + } else { + if (protocol != PROTOCOL_HTTP_PROTOBUF && protocol != PROTOCOL_HTTP_JSON) { + LOG4CXX_WARN(mLogger, "Received unknown OTLP protocol: " << protocol + << ". Will use default(http/protobuf)"); } - } - exporter.reset(new opentelemetry::exporter::otlp::OtlpGrpcExporter(opts)); + opentelemetry::exporter::otlp::OtlpHttpExporterOptions opts; + opts.url = config->getOtelExporterEndpoint(); + + if (protocol == PROTOCOL_HTTP_JSON) { + opts.content_type = opentelemetry::exporter::otlp::HttpRequestContentType::kJson; + } + + if (config->getOtelSslEnabled()) { + opts.ssl_ca_cert_path = config->getOtelSslCertPath(); + LOG4CXX_TRACE(mLogger, "Ssl Credentials are enabled for exporter, path: " + << opts.ssl_ca_cert_path); + } + + opentelemetry::common::KeyValueStringTokenizer tokenizer{config->getOtelExporterOtlpHeaders()}; + opentelemetry::nostd::string_view header_key; + opentelemetry::nostd::string_view header_value; + bool header_valid = true; + std::unordered_set remove_cache; + + while (tokenizer.next(header_valid, header_key, header_value)) + { + if (header_valid) + { + std::string key = static_cast(header_key); + if (remove_cache.end() == remove_cache.find(key)) + { + remove_cache.insert(key); + auto it = opts.http_headers.find(key); + if (it != opts.http_headers.end()) + { + opts.http_headers.erase(it); + } + } + + opts.http_headers[std::move(key)] = static_cast(header_value); + } + } + + exporter.reset(new opentelemetry::exporter::otlp::OtlpHttpExporter(opts)); + } } LOG4CXX_INFO(mLogger, "Exporter created with ExporterType: " diff --git a/instrumentation/otel-webserver-module/src/nginx/ngx_http_opentelemetry_module.c b/instrumentation/otel-webserver-module/src/nginx/ngx_http_opentelemetry_module.c index aa1f34bd3..e928b1079 100644 --- a/instrumentation/otel-webserver-module/src/nginx/ngx_http_opentelemetry_module.c +++ b/instrumentation/otel-webserver-module/src/nginx/ngx_http_opentelemetry_module.c @@ -250,6 +250,13 @@ static ngx_command_t ngx_http_opentelemetry_commands[] = { offsetof(ngx_http_opentelemetry_loc_conf_t, nginxModuleOtelExporterOtlpHeaders), NULL}, + { ngx_string("NginxModuleOtelExporterOtlpProtocol"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_opentelemetry_loc_conf_t, nginxModuleOtelExporterOtlpProtocol), + NULL}, + { ngx_string("NginxModuleOtelSpanProcessor"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_str_slot, @@ -540,6 +547,7 @@ static char* ngx_http_opentelemetry_merge_loc_conf(ngx_conf_t *cf, void *parent, ngx_conf_merge_str_value(conf->nginxModuleOtelSpanExporter, prev->nginxModuleOtelSpanExporter, ""); ngx_conf_merge_str_value(conf->nginxModuleOtelExporterEndpoint, prev->nginxModuleOtelExporterEndpoint, ""); ngx_conf_merge_str_value(conf->nginxModuleOtelExporterOtlpHeaders, prev->nginxModuleOtelExporterOtlpHeaders, ""); + ngx_conf_merge_str_value(conf->nginxModuleOtelExporterOtlpProtocol, prev->nginxModuleOtelExporterOtlpProtocol, ""); ngx_conf_merge_value(conf->nginxModuleOtelSslEnabled, prev->nginxModuleOtelSslEnabled, 0); ngx_conf_merge_str_value(conf->nginxModuleOtelSslCertificatePath, prev->nginxModuleOtelSslCertificatePath, ""); ngx_conf_merge_str_value(conf->nginxModuleOtelSpanProcessor, prev->nginxModuleOtelSpanProcessor, ""); @@ -1403,6 +1411,11 @@ static ngx_flag_t ngx_initialize_opentelemetry(ngx_http_request_t *r) env_config[ix].value = (const char*)(conf->nginxModuleOtelExporterOtlpHeaders).data; ++ix; + // Otel Exporter OTLP Protocol + env_config[ix].name = OTEL_SDK_ENV_OTEL_EXPORTER_OTLP_PROTOCOL; + env_config[ix].value = (const char*)(conf->nginxModuleOtelExporterOtlpProtocol).data; + ++ix; + // Otel SSL Enabled env_config[ix].name = OTEL_SDK_ENV_OTEL_SSL_ENABLED; env_config[ix].value = conf->nginxModuleOtelSslEnabled == 1 ? "1" : "0"; diff --git a/instrumentation/otel-webserver-module/src/nginx/ngx_http_opentelemetry_module.h b/instrumentation/otel-webserver-module/src/nginx/ngx_http_opentelemetry_module.h index 250ca1281..684971b04 100644 --- a/instrumentation/otel-webserver-module/src/nginx/ngx_http_opentelemetry_module.h +++ b/instrumentation/otel-webserver-module/src/nginx/ngx_http_opentelemetry_module.h @@ -23,7 +23,7 @@ #define LOWEST_HTTP_ERROR_CODE 400 #define STATUS_CODE_BYTE_COUNT 6 -static const int CONFIG_COUNT = 18; // Number of key value pairs in config +static const int CONFIG_COUNT = 19; // Number of key value pairs in config static const int TRACE_ID_LEN = 32; // Length of trace_id static const int SPAN_ID_LEN = 16; // Length of span_id static const char NGINX_VARIABLE_IDENTIFIER = '$'; // Identifier for Nginx variables @@ -107,6 +107,7 @@ typedef struct { ngx_str_t nginxModuleRequestHeaders; ngx_str_t nginxModuleResponseHeaders; ngx_str_t nginxModuleOtelExporterOtlpHeaders; + ngx_str_t nginxModuleOtelExporterOtlpProtocol; ngx_flag_t nginxModuleTrustIncomingSpans; ngx_array_t *nginxModuleAttributes; ngx_array_t *nginxModuleIgnorePaths;