diff --git a/api/wasm/cpp/doc/wasm_filter.md b/api/wasm/cpp/doc/wasm_filter.md index 14b3ab326a..91e97c1efb 100644 --- a/api/wasm/cpp/doc/wasm_filter.md +++ b/api/wasm/cpp/doc/wasm_filter.md @@ -675,6 +675,14 @@ method is effective when calling from Returns [WasmData](#wasmdata) pointer which holds the response body data. +### activeSpanSetTag + +``` {.sourceCode .cpp} +void activeSpanSetTag(StringView key, StringView value) +``` +Sets a tag key and value in the active span of the request being +processed by the filte. + Metadata API ------------ diff --git a/api/wasm/cpp/proxy_wasm_api.h b/api/wasm/cpp/proxy_wasm_api.h index 2a21f7266e..108263c849 100644 --- a/api/wasm/cpp/proxy_wasm_api.h +++ b/api/wasm/cpp/proxy_wasm_api.h @@ -169,6 +169,7 @@ struct Tuple3Hash { }; using HeaderStringPairs = std::vector>; +using SpanTagPairs = std::vector>; class GrpcCallHandlerBase { public: @@ -785,6 +786,11 @@ inline WasmResult makeHttpCall(StringView uri, const HeaderStringPairs& request_ return result; } +// Tracing +inline WasmResult activeSpanSetTag(StringView key, StringView value) { + return proxy_set_active_span_tag(key.data(), key.size(), value.data(), value.size()); +} + // Low level metrics interface. inline WasmResult defineMetric(MetricType type, StringView name, uint32_t* metric_id) { diff --git a/api/wasm/cpp/proxy_wasm_externs.h b/api/wasm/cpp/proxy_wasm_externs.h index aabb64ce07..212b5290fe 100644 --- a/api/wasm/cpp/proxy_wasm_externs.h +++ b/api/wasm/cpp/proxy_wasm_externs.h @@ -89,6 +89,10 @@ extern "C" WasmResult proxy_remove_header_map_value(HeaderMapType type, const ch size_t key_size); extern "C" WasmResult proxy_get_header_map_size(HeaderMapType type, size_t* size); +// Tracing +extern "C" WasmResult proxy_set_active_span_tag(const char* key_ptr, size_t key_size, const char* value_ptr, + size_t value_size); + // Buffer extern "C" WasmResult proxy_get_buffer_bytes(BufferType type, uint32_t start, uint32_t length, const char** ptr, size_t* size); diff --git a/api/wasm/cpp/proxy_wasm_intrinsics.js b/api/wasm/cpp/proxy_wasm_intrinsics.js index a6393ea19d..be5d9aa05a 100644 --- a/api/wasm/cpp/proxy_wasm_intrinsics.js +++ b/api/wasm/cpp/proxy_wasm_intrinsics.js @@ -38,4 +38,5 @@ mergeInto(LibraryManager.library, { proxy_set_effective_context : function () {}, proxy_done: function () {}, proxy_call_foreign_function: function () {}, + proxy_set_active_span_tag: function () {}, }); diff --git a/examples/wasm/envoy_filter_http_wasm_example.wasm b/examples/wasm/envoy_filter_http_wasm_example.wasm index 1f282df4a1..4278debec7 100644 Binary files a/examples/wasm/envoy_filter_http_wasm_example.wasm and b/examples/wasm/envoy_filter_http_wasm_example.wasm differ diff --git a/source/extensions/common/wasm/context.cc b/source/extensions/common/wasm/context.cc index 485dcd851e..e93109fd8a 100644 --- a/source/extensions/common/wasm/context.cc +++ b/source/extensions/common/wasm/context.cc @@ -1106,6 +1106,15 @@ void Context::scriptLog(spdlog::level::level_enum level, absl::string_view messa // Connection bool Context::isSsl() { return decoder_callbacks_->connection()->ssl() != nullptr; } +// Tracing +void Context::activeSpanSetTag(absl::string_view key, absl::string_view value) { + if (!decoder_callbacks_) { + return; + } + Tracing::Span& span = decoder_callbacks_->activeSpan(); + span.setTag(key, value); +} + // // Calls into the WASM code. // diff --git a/source/extensions/common/wasm/context.h b/source/extensions/common/wasm/context.h index 34ca6e0376..2228b1998d 100644 --- a/source/extensions/common/wasm/context.h +++ b/source/extensions/common/wasm/context.h @@ -332,6 +332,9 @@ class Context : public Logger::Loggable, // Connection virtual bool isSsl(); + // Tracing + virtual void activeSpanSetTag(absl::string_view key, absl::string_view value); + void addAfterVmCallAction(std::function f); protected: diff --git a/source/extensions/common/wasm/exports.cc b/source/extensions/common/wasm/exports.cc index 36ee6cdc42..c3a6ae0215 100644 --- a/source/extensions/common/wasm/exports.cc +++ b/source/extensions/common/wasm/exports.cc @@ -1,3 +1,5 @@ +#include + #include "extensions/common/wasm/wasm.h" namespace Envoy { @@ -846,6 +848,18 @@ Word log(void* raw_context, Word level, Word address, Word size) { return wasmResultToWord(WasmResult::Ok); } +Word set_active_span_tag(void* raw_context, Word key_ptr, Word key_size, Word value_ptr, + Word value_size) { + auto context = WASM_CONTEXT(raw_context); + auto key = context->wasmVm()->getMemory(key_ptr.u64_, key_size.u64_); + auto value = context->wasmVm()->getMemory(value_ptr.u64_, value_size.u64_); + if (!key || !value) { + return wasmResultToWord(WasmResult::InvalidMemoryAccess); + } + context->activeSpanSetTag(key.value(), value.value()); + return wasmResultToWord(WasmResult::Ok); +} + } // namespace Exports } // namespace Wasm } // namespace Common diff --git a/source/extensions/common/wasm/exports.h b/source/extensions/common/wasm/exports.h index 79326caca4..1e25cab633 100644 --- a/source/extensions/common/wasm/exports.h +++ b/source/extensions/common/wasm/exports.h @@ -79,6 +79,8 @@ Word set_effective_context(void* raw_context, Word context_id); Word done(void* raw_context); Word call_foreign_function(void* raw_context, Word function_name, Word function_name_size, Word arguments, Word warguments_size, Word results, Word results_size); +Word set_active_span_tag(void* raw_context, Word key_ptr, Word key_size, Word value_ptr, + Word value_size); // Runtime environment functions exported from envoy to wasm. diff --git a/source/extensions/common/wasm/null/wasm_api_impl.h b/source/extensions/common/wasm/null/wasm_api_impl.h index 72e1f0a346..5183385690 100644 --- a/source/extensions/common/wasm/null/wasm_api_impl.h +++ b/source/extensions/common/wasm/null/wasm_api_impl.h @@ -98,7 +98,7 @@ inline WasmResult proxy_set_shared_data(const char* key_ptr, size_t key_size, co } // SharedQueue -// Note: Registering the same queue_name will overwrite the old registration while preseving any +// Note: Registering the same queue_name will overwrite the old registration while preserving any // pending data. Consequently it should typically be followed by a call to // proxy_dequeue_shared_queue. Returns unique token for the queue. inline WasmResult proxy_register_shared_queue(const char* queue_name_ptr, size_t queue_name_size, @@ -225,6 +225,13 @@ inline WasmResult proxy_grpc_send(uint64_t token, const char* message_ptr, size_ WS(message_size), WS(end_stream))); } +// Tracing +inline WasmResult proxy_set_active_span_tag(const char* key_ptr, size_t key_size, + const char* value_ptr, size_t value_size) { + return wordToWasmResult(Exports::set_active_span_tag(current_context_, WR(key_ptr), WS(key_size), + WR(value_ptr), WS(value_size))); +} + // Metrics // Returns a metric_id which can be used to report a metric. On error returns 0. inline WasmResult proxy_define_metric(MetricType type, const char* name_ptr, size_t name_size, diff --git a/source/extensions/common/wasm/wasm.cc b/source/extensions/common/wasm/wasm.cc index 0be23f9da5..bd495deca2 100644 --- a/source/extensions/common/wasm/wasm.cc +++ b/source/extensions/common/wasm/wasm.cc @@ -209,6 +209,7 @@ void Wasm::registerCallbacks() { _REGISTER_PROXY(set_effective_context); _REGISTER_PROXY(done); _REGISTER_PROXY(call_foreign_function); + _REGISTER_PROXY(set_active_span_tag); #undef _REGISTER_PROXY } diff --git a/test/extensions/access_loggers/wasm/test_data/logging.wasm b/test/extensions/access_loggers/wasm/test_data/logging.wasm index 045900c28a..2ec42bd733 100644 Binary files a/test/extensions/access_loggers/wasm/test_data/logging.wasm and b/test/extensions/access_loggers/wasm/test_data/logging.wasm differ diff --git a/test/extensions/filters/http/wasm/test_data/Makefile b/test/extensions/filters/http/wasm/test_data/Makefile index 4f02e7a15d..002683ca6d 100644 --- a/test/extensions/filters/http/wasm/test_data/Makefile +++ b/test/extensions/filters/http/wasm/test_data/Makefile @@ -1,3 +1,3 @@ -all: headers_cpp.wasm async_call_cpp.wasm metadata_cpp.wasm grpc_call_cpp.wasm shared_cpp.wasm queue_cpp.wasm root_id_cpp.wasm body_cpp.wasm +all: headers_cpp.wasm async_call_cpp.wasm metadata_cpp.wasm grpc_call_cpp.wasm shared_cpp.wasm queue_cpp.wasm root_id_cpp.wasm body_cpp.wasm tracing_cpp.wasm include ../../../../../../api/wasm/cpp/Makefile.base_lite diff --git a/test/extensions/filters/http/wasm/test_data/Makefile.docker_cpp_builder b/test/extensions/filters/http/wasm/test_data/Makefile.docker_cpp_builder index c6dbea3473..ad679eeb59 100644 --- a/test/extensions/filters/http/wasm/test_data/Makefile.docker_cpp_builder +++ b/test/extensions/filters/http/wasm/test_data/Makefile.docker_cpp_builder @@ -1,6 +1,6 @@ DOCKER_SDK=/external_sdk -all: headers_cpp.wasm async_call_cpp.wasm metadata_cpp.wasm grpc_call_cpp.wasm shared_cpp.wasm queue_cpp.wasm http_callout_cpp.wasm grpc_callout_cpp.wasm +all: headers_cpp.wasm async_call_cpp.wasm metadata_cpp.wasm grpc_call_cpp.wasm shared_cpp.wasm queue_cpp.wasm http_callout_cpp.wasm grpc_callout_cpp.wasm tracing_cpp.wasm chown ${uid}.${gid} *.wasm include ${DOCKER_SDK}/Makefile.base_lite diff --git a/test/extensions/filters/http/wasm/test_data/async_call_cpp.wasm b/test/extensions/filters/http/wasm/test_data/async_call_cpp.wasm index 663721acc6..507a3d10c2 100644 Binary files a/test/extensions/filters/http/wasm/test_data/async_call_cpp.wasm and b/test/extensions/filters/http/wasm/test_data/async_call_cpp.wasm differ diff --git a/test/extensions/filters/http/wasm/test_data/grpc_call_cpp.wasm b/test/extensions/filters/http/wasm/test_data/grpc_call_cpp.wasm index d1ace7c506..a3cab62d53 100644 Binary files a/test/extensions/filters/http/wasm/test_data/grpc_call_cpp.wasm and b/test/extensions/filters/http/wasm/test_data/grpc_call_cpp.wasm differ diff --git a/test/extensions/filters/http/wasm/test_data/grpc_callout_cpp.wasm b/test/extensions/filters/http/wasm/test_data/grpc_callout_cpp.wasm new file mode 100644 index 0000000000..bb5a64bda0 Binary files /dev/null and b/test/extensions/filters/http/wasm/test_data/grpc_callout_cpp.wasm differ diff --git a/test/extensions/filters/http/wasm/test_data/headers_cpp.wasm b/test/extensions/filters/http/wasm/test_data/headers_cpp.wasm index 045900c28a..2ec42bd733 100644 Binary files a/test/extensions/filters/http/wasm/test_data/headers_cpp.wasm and b/test/extensions/filters/http/wasm/test_data/headers_cpp.wasm differ diff --git a/test/extensions/filters/http/wasm/test_data/http_callout_cpp.wasm b/test/extensions/filters/http/wasm/test_data/http_callout_cpp.wasm new file mode 100644 index 0000000000..cea506cc62 Binary files /dev/null and b/test/extensions/filters/http/wasm/test_data/http_callout_cpp.wasm differ diff --git a/test/extensions/filters/http/wasm/test_data/metadata_cpp.wasm b/test/extensions/filters/http/wasm/test_data/metadata_cpp.wasm index badf023368..3bb82532e8 100644 Binary files a/test/extensions/filters/http/wasm/test_data/metadata_cpp.wasm and b/test/extensions/filters/http/wasm/test_data/metadata_cpp.wasm differ diff --git a/test/extensions/filters/http/wasm/test_data/queue_cpp.wasm b/test/extensions/filters/http/wasm/test_data/queue_cpp.wasm index 52ac03b6f9..21870d5362 100644 Binary files a/test/extensions/filters/http/wasm/test_data/queue_cpp.wasm and b/test/extensions/filters/http/wasm/test_data/queue_cpp.wasm differ diff --git a/test/extensions/filters/http/wasm/test_data/shared_cpp.wasm b/test/extensions/filters/http/wasm/test_data/shared_cpp.wasm index d5133eac66..13a8ca529d 100644 Binary files a/test/extensions/filters/http/wasm/test_data/shared_cpp.wasm and b/test/extensions/filters/http/wasm/test_data/shared_cpp.wasm differ diff --git a/test/extensions/filters/http/wasm/test_data/tracing_cpp.cc b/test/extensions/filters/http/wasm/test_data/tracing_cpp.cc new file mode 100644 index 0000000000..cf3c0a1fac --- /dev/null +++ b/test/extensions/filters/http/wasm/test_data/tracing_cpp.cc @@ -0,0 +1,18 @@ +// NOLINT(namespace-envoy) +#include +#include + +#include "proxy_wasm_intrinsics.h" + +class ExampleContext : public Context { +public: + explicit ExampleContext(uint32_t id, RootContext* root) : Context(id, root) {} + + FilterHeadersStatus onRequestHeaders(uint32_t) override; +}; +static RegisterContextFactory register_ExampleContext(CONTEXT_FACTORY(ExampleContext)); + +FilterHeadersStatus ExampleContext::onRequestHeaders(uint32_t) { + activeSpanSetTag("tag_1", "tag_value_1"); + return FilterHeadersStatus::Continue; +} \ No newline at end of file diff --git a/test/extensions/filters/http/wasm/test_data/tracing_cpp.wasm b/test/extensions/filters/http/wasm/test_data/tracing_cpp.wasm new file mode 100644 index 0000000000..f9dd706e66 Binary files /dev/null and b/test/extensions/filters/http/wasm/test_data/tracing_cpp.wasm differ diff --git a/test/extensions/filters/http/wasm/wasm_filter_test.cc b/test/extensions/filters/http/wasm/wasm_filter_test.cc index 50432ab893..5050f0bc91 100644 --- a/test/extensions/filters/http/wasm/wasm_filter_test.cc +++ b/test/extensions/filters/http/wasm/wasm_filter_test.cc @@ -16,6 +16,7 @@ #include "test/mocks/ssl/mocks.h" #include "test/mocks/stream_info/mocks.h" #include "test/mocks/thread_local/mocks.h" +#include "test/mocks/tracing/mocks.h" #include "test/mocks/upstream/mocks.h" #include "test/test_common/environment.h" #include "test/test_common/printers.h" @@ -149,6 +150,7 @@ class WasmHttpFilterTest : public testing::TestWithParam { NiceMock encoder_callbacks_; NiceMock request_stream_info_; NiceMock local_info_; + NiceMock active_span_; envoy::config::core::v3::Metadata listener_metadata_; TestRoot* root_context_ = nullptr; Config::DataSource::RemoteAsyncDataProviderPtr remote_data_provider_; @@ -759,6 +761,18 @@ TEST_P(WasmHttpFilterTest, SharedQueue) { wasm_->wasm()->queueReady(root_context_->id(), token); } +// Verifies if the tags have been added correctly. +TEST_P(WasmHttpFilterTest, AddTagToActiveSpans) { + setupConfig(TestEnvironment::readFileToStringForTest(TestEnvironment::substitute( + "{{ test_rundir }}/test/extensions/filters/http/wasm/test_data/tracing_cpp.wasm"))); + setupFilter(); + EXPECT_CALL(decoder_callbacks_, activeSpan).WillRepeatedly(ReturnRef(active_span_)); + EXPECT_CALL(active_span_, setTag(Eq("tag_1"), Eq("tag_value_1"))); + Http::TestRequestHeaderMapImpl request_headers{{":path", "/"}}; + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); + filter_->onDestroy(); +} + // Script using a root_id which is not registered. TEST_P(WasmHttpFilterTest, RootIdNotRegistered) { setupConfig(TestEnvironment::readFileToStringForTest(TestEnvironment::substitute( diff --git a/tools/spelling/spelling_dictionary.txt b/tools/spelling/spelling_dictionary.txt index a910f1fe64..9f3fac68bc 100644 --- a/tools/spelling/spelling_dictionary.txt +++ b/tools/spelling/spelling_dictionary.txt @@ -68,14 +68,17 @@ DW EADDRINUSE EADDRNOTAVAIL EAGAIN +EBADF ECDH ECDHE ECDSA ECDSAs ECMP +ECONNREFUSE ECONNREFUSED EDESTRUCTION EDF +EFAULT EINVAL ELB ENOTFOUND @@ -86,6 +89,7 @@ EOS EPOLLRDHUP EQ ERANGE +ESUCCESS EV EVAL EVLOOP @@ -114,6 +118,7 @@ GCOVR GCP GETting GLB +GNUC GOAWAY GRPC GTEST @@ -143,8 +148,10 @@ IPV IPs IPv ITOA +IWYU Isode Iters +JS JSON JSONs JWKS @@ -214,6 +221,7 @@ PGV PID PKTINFO PNG +Plulgin PostCBs PREBIND PRNG @@ -254,6 +262,7 @@ SAN SCT SDK SDS +SEGV SENDSRCADDR SHA SHM @@ -273,6 +282,7 @@ SPIFFE SPKI SQL SR +SRCDIR SRDS SRV SS @@ -319,6 +329,7 @@ VHDS VLOG VM WASM +WASI WAVM WIP WKT @@ -363,6 +374,7 @@ argv artisanal ary asctime +asm async atoi atomicity @@ -385,6 +397,7 @@ backticks balancer balancers barbaz +basename baz bazel behaviour @@ -411,6 +424,7 @@ bursty bytecode cacheability callee +callout callsite callsites callstack @@ -430,10 +444,12 @@ chrono chroot chunked ci +ciovec ciphersuite ciphersuites circllhist CITT +clonable cloneable cloneability cmd @@ -444,6 +460,7 @@ codecs codepath codings combinatorial +commmon comparator compat completable @@ -471,8 +488,10 @@ cryptographically cstate cstring ctor +ctors ctrl customizations +cxa darwin datadog datagram @@ -499,6 +518,7 @@ deletable deleter delim deque +dequeue deprecations dereference dereferences @@ -520,16 +540,20 @@ dgst dir dirname djb +downcall +downcalls downcasted downstreams dtor dubbo dup durations +dynamictop dynamodb emplace emplaced emscripten +emsdk enablement encodings endian @@ -540,7 +564,9 @@ enqueued enqueues enum enums +environ epoll +eproto errno etag etags @@ -551,6 +577,7 @@ evented evwatch exe execlp +exitcode exprfor expectable extrahelp @@ -563,13 +590,18 @@ favicon fcntl fd fds +filedelta filename filenames fileno +filesize filesystem +fintrinsics firefox fixdate fixup +fld +flite fmt fmtlib fn @@ -581,6 +613,8 @@ ftruncate func functor functors +functtions +fwasm gRPC gcov genrule @@ -624,17 +658,21 @@ hrefs huffman hystrix idempotency +ident +identifiying idx ifdef iff ified impl +implemenation implementors impls inflater inflight -ing init +initate initializer inlined inlining @@ -644,10 +682,13 @@ instantiation instantiations interpretable intra +intrinsics ints invariance +iov iovec iovecs +iovs ips iptables ish @@ -669,6 +710,9 @@ kv kvs lala latencies +ld +ldb +ldd len lenenc lexically @@ -742,13 +786,16 @@ mux muxed mysql namespace +namespaced namespaces namespacing nan +nano natively netblock netblocks netfilter +newoffset nonblocking noncopyable nonresponsive @@ -763,6 +810,7 @@ nullopt nullptr num numkeys +nwritten observability ocagent offsetof @@ -802,6 +850,7 @@ pausable pcall pcap pclose +percompiled pfctl pipelined pipelining @@ -814,6 +863,7 @@ pos posix postfix postfixes +pragma pre preallocate preallocating @@ -829,6 +879,8 @@ preflight preorder prepend prepended +prepending +preseving prev proc profiler @@ -925,6 +977,8 @@ ruleset runfiles runtime runtimes +rval +rvalue rver rxhash sandboxed @@ -1009,6 +1063,7 @@ subtypes subzone superclass superset +suppoorted symlink symlinked symlinks @@ -1025,6 +1080,7 @@ tcmalloc tcpdump teardown tempdir +tempdouble templated templating templatize @@ -1081,6 +1137,7 @@ unref unreferenced unzigzag upcasts +upstreaming upstreams uptime upvalue @@ -1094,6 +1151,7 @@ utils valgrind validator validators +valueor vanishingly varchar variadic