From 3e1cdd5fc2e5ca6f972b88220549105ca1cfda30 Mon Sep 17 00:00:00 2001 From: roketyyang Date: Sun, 10 Sep 2023 20:08:05 +0800 Subject: [PATCH] feat: support array_value attribute type, closes #82 --- README.md | 4 ++ examples/openresty/nginx.conf | 14 ++++- lib/opentelemetry/attribute.lua | 60 +++++++++++++++++++ .../semantic_conventions/trace/http.lua | 47 ++++++++++++++- 4 files changed, 123 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c91c8fc..c71f78d 100644 --- a/README.md +++ b/README.md @@ -81,12 +81,16 @@ local cur_span_context = context:span_context() local attr = require("opentelemetry.attribute") -- string attribute attr.string("service.name", "openresty") +attr.string_array("service.name", {"openresty"}) -- int attribute attr.int("attr_int", 100) +attr.int_array("attr_ints", {100, 1000}) -- double attribute attr.double("attr_double", 10.24) +attr.double_array("attr_doubles", {10.24, 20.48}) -- bool attribute attr.bool("attr_bool", true) +attr.bool_array("attr_bools", {true, false}) ``` ## Resource diff --git a/examples/openresty/nginx.conf b/examples/openresty/nginx.conf index 5d2fcfc..79fa449 100644 --- a/examples/openresty/nginx.conf +++ b/examples/openresty/nginx.conf @@ -91,6 +91,7 @@ server { local span_kind = require("opentelemetry.trace.span_kind") + local http_conv = require("opentelemetry.semantic_conventions.trace.http") local attr = require("opentelemetry.attribute") local context = require("opentelemetry.context").new() local trace_context_propagator = require("opentelemetry.trace.propagation.text_map.trace_context_propagator").new() @@ -101,9 +102,17 @@ server { -- extract trace context from the headers of downstream HTTP request context = composite_propagator:extract(context, ngx.req) + local attributes = http_conv.request_header(ngx.req.get_headers()) + table.insert(attributes, attr.string_array("attr_strings", {"opentelemetry", "lua"})) + table.insert(attributes, attr.int("attr_int", 1024)) + table.insert(attributes, attr.int_array("attr_ints", {1024, 2048})) + table.insert(attributes, attr.double("attr_double", 10.24)) + table.insert(attributes, attr.double_array("attr_doubles", {10.24, 20.48})) + table.insert(attributes, attr.bool("attr_bool", true)) + table.insert(attributes, attr.bool_array("attr_bools", {true, false})) local context, span = tracer:start(context, "access_by_lua_block", { kind = span_kind.internal, - attributes = {attr.double("attr_double", 10.24), attr.bool("attr_bool", true)}, + attributes = attributes, }) context:attach() @@ -121,7 +130,10 @@ server { -- get tracer from current context local tracer = context.current():span():tracer_provider():tracer("opentelemetry-lua") + local http_conv = require("opentelemetry.semantic_conventions.trace.http") + local resp_attrs = http_conv.response_header(ngx.resp.get_headers()) local context, sub_span = tracer:start(context.current(), "header_filter_by_lua_block") + sub_span:set_attributes(unpack(resp_attrs)) sub_span:record_error("this is err") sub_span:set_status(span_status.ERROR, "set status err") sub_span:add_event("event1", {attributes = {attr.string("attr_string", "attr_value")}}) diff --git a/lib/opentelemetry/attribute.lua b/lib/opentelemetry/attribute.lua index ca6db1f..ec5fac3 100644 --- a/lib/opentelemetry/attribute.lua +++ b/lib/opentelemetry/attribute.lua @@ -9,6 +9,21 @@ function _M.string(key, value) } end +function _M.string_array(key, values) + local ret = { + key = key, + value = { + array_value = { + values = {} + } + } + } + for i = 1, #values do + table.insert(ret.value.array_value.values, {string_value = values[i]}) + end + return ret +end + function _M.int(key, value) return { key = key, @@ -18,6 +33,21 @@ function _M.int(key, value) } end +function _M.int_array(key, values) + local ret = { + key = key, + value = { + array_value = { + values = {} + } + } + } + for i = 1, #values do + table.insert(ret.value.array_value.values, {int_value = values[i]}) + end + return ret +end + function _M.bool(key, value) return { key = key, @@ -27,6 +57,21 @@ function _M.bool(key, value) } end +function _M.bool_array(key, values) + local ret = { + key = key, + value = { + array_value = { + values = {} + } + } + } + for i = 1, #values do + table.insert(ret.value.array_value.values, {bool_value = values[i]}) + end + return ret +end + function _M.double(key, value) return { key = key, @@ -36,4 +81,19 @@ function _M.double(key, value) } end +function _M.double_array(key, values) + local ret = { + key = key, + value = { + array_value = { + values = {} + } + } + } + for i = 1, #values do + table.insert(ret.value.array_value.values, {double_value = values[i]}) + end + return ret +end + return _M \ No newline at end of file diff --git a/lib/opentelemetry/semantic_conventions/trace/http.lua b/lib/opentelemetry/semantic_conventions/trace/http.lua index 005701b..a7dbd8c 100644 --- a/lib/opentelemetry/semantic_conventions/trace/http.lua +++ b/lib/opentelemetry/semantic_conventions/trace/http.lua @@ -2,6 +2,8 @@ -- See: https://github.com/open-telemetry/opentelemetry-specification/tree/main/specification/trace/semantic_conventions -- -- module @semantic_conventions.trace.http +local attribute = require("opentelemetry.attribute") + local _M = { -- HTTP request method. HTTP_METHOD = "http.method", @@ -26,6 +28,49 @@ local _M = { -- The matched route (path template in the format used by the respective server framework). See note below HTTP_ROUTE = "http.route", -- The IP address of the original client behind all proxies, if known (e.g. from [X-Forwarded-For](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For)). - HTTP_CLIENT_IP = "http.client_ip" + HTTP_CLIENT_IP = "http.client_ip", + -- The opentelemetry attribute key prefix for HTTP request headers + HTTP_REQUEST_HEADER = "http.request.header", + -- The opentelemetry attribute key prefix for HTTP response headers + HTTP_RESPONSE_HEADER = "http.response.header", } + +------------------------------------------------------------------ +-- returns the contents of headers as OpenTelemetry attributes. +-- +-- @headers a table of HTTP request headers +-- @return a table of attribute +------------------------------------------------------------------ +function _M.request_header(headers) + local attributes = {} + for k, v in pairs(headers) do + k = _M.HTTP_REQUEST_HEADER .. '.' .. k + if type(v) == "table" then + table.insert(attributes, attribute.string_array(k, v)) + else + table.insert(attributes, attribute.string(k, v)) + end + end + return attributes +end + +------------------------------------------------------------------ +-- returns the contents of headers as OpenTelemetry attributes. +-- +-- @headers a table of HTTP response headers +-- @return a table of attribute +------------------------------------------------------------------ +function _M.response_header(headers) + local attributes = {} + for k, v in pairs(headers) do + k = _M.HTTP_RESPONSE_HEADER .. '.' .. k + if type(v) == "table" then + table.insert(attributes, attribute.string_array(k, v)) + else + table.insert(attributes, attribute.string(k, v)) + end + end + return attributes +end + return _M