local Queue = require "kong.tools.queue" local o11y_logs = require "kong.observability.logs" local otlp = require "kong.observability.otlp" local tracing_context = require "kong.observability.tracing.tracing_context" local otel_utils = require "kong.plugins.opentelemetry.utils" local clone = require "table.clone" local table_concat = require "kong.tools.table".concat local ngx = ngx local ngx_log = ngx.log local ngx_ERR = ngx.ERR local ngx_DEBUG = ngx.DEBUG local http_export_request = otel_utils.http_export_request local get_headers = otel_utils.get_headers local _log_prefix = otel_utils._log_prefix local encode_logs = otlp.encode_logs local prepare_logs = otlp.prepare_logs local function http_export_logs(params, logs_batch) local conf = params.conf local resource_attributes = params.options.compiled_resource_attributes or conf.resource_attributes local headers = get_headers(conf.headers) local payload = encode_logs(logs_batch, resource_attributes) local ok, err = http_export_request({ connect_timeout = conf.connect_timeout, send_timeout = conf.send_timeout, read_timeout = conf.read_timeout, endpoint = conf.logs_endpoint, }, payload, headers) if ok then ngx_log(ngx_DEBUG, _log_prefix, "exporter sent ", #logs_batch, " logs to ", conf.logs_endpoint) else ngx_log(ngx_ERR, _log_prefix, err) end return ok, err end local function log(conf, options) local worker_logs = o11y_logs.get_worker_logs() local request_logs = o11y_logs.get_request_logs() local worker_logs_len = #worker_logs local request_logs_len = #request_logs ngx_log(ngx_DEBUG, _log_prefix, "total request_logs in current request: ", request_logs_len, " total worker_logs in current request: ", worker_logs_len) if request_logs_len + worker_logs_len == 0 then return end local raw_trace_id = tracing_context.get_raw_trace_id() local flags = tracing_context.get_flags() local worker_logs_ready = prepare_logs(worker_logs) local request_logs_ready = prepare_logs(request_logs, raw_trace_id, flags) local params = { conf = conf, options = options, } local queue_conf = clone(Queue.get_plugin_params("opentelemetry", conf)) queue_conf.name = queue_conf.name .. ":logs" for _, log in ipairs(table_concat(worker_logs_ready, request_logs_ready)) do -- Check if the entry can be enqueued before calling `Queue.enqueue` -- This is done because newer logs are not more important than old ones. -- Enqueueing without checking would result in older logs being dropped -- which affects performance because it's done synchronously. if Queue.can_enqueue(queue_conf, log) then Queue.enqueue( queue_conf, http_export_logs, params, log ) end end end return { log = log, }