snapshot of https://github.com/jitsi/jitsi-meet.git @ fd1749dd28f4138aa80234fc7f311b19aaffa0e7 (2026-09-15)
This commit is contained in:
203
resources/prosody-plugins/otel.lib.lua
Normal file
203
resources/prosody-plugins/otel.lib.lua
Normal file
@@ -0,0 +1,203 @@
|
||||
-- This opentelemetry library was inspired by https://github.com/yangxikun/opentelemetry-lua,
|
||||
-- but simplified and adapted to the Prosody ecosystem.
|
||||
|
||||
local json = require "util.json"
|
||||
local array = require "util.array"
|
||||
local time = require "util.time"
|
||||
local random = require "util.random"
|
||||
local hex = require "util.hex"
|
||||
|
||||
local m = {}
|
||||
|
||||
--------------------------------------------------
|
||||
-- Util --
|
||||
--------------------------------------------------
|
||||
|
||||
local function random_hex(n)
|
||||
return hex.to(random.bytes(n))
|
||||
end
|
||||
local function to_nanoseconds(t)
|
||||
return tostring(math.floor(t * 1e9))
|
||||
end
|
||||
|
||||
|
||||
--------------------------------------------------
|
||||
-- Attribute --
|
||||
--------------------------------------------------
|
||||
|
||||
local Attribute = {}
|
||||
m.Attribute = Attribute
|
||||
|
||||
function Attribute.string(value)
|
||||
return {
|
||||
string_value = value
|
||||
}
|
||||
end
|
||||
|
||||
--------------------------------------------------
|
||||
-- Span --
|
||||
--------------------------------------------------
|
||||
|
||||
local SpanStatus = {
|
||||
UNSET = 0,
|
||||
OK = 1,
|
||||
ERROR = 2,
|
||||
}
|
||||
|
||||
local SpanKind = {
|
||||
UNSPECIFIED = 0,
|
||||
INTERNAL = 1,
|
||||
SERVER = 2,
|
||||
CLIENT = 3,
|
||||
PRODUCER = 4,
|
||||
CONSUMER = 5,
|
||||
}
|
||||
|
||||
local Span = {}
|
||||
Span.__index = Span
|
||||
m.Span = Span
|
||||
|
||||
function Span.new(name, tracer, opts)
|
||||
local self = {
|
||||
name = name,
|
||||
tracer = tracer,
|
||||
parent_context = opts.context,
|
||||
trace_id = opts.context and opts.context.trace_id or random_hex(16),
|
||||
span_id = random_hex(8),
|
||||
start_time = time.now(),
|
||||
attributes = array {},
|
||||
}
|
||||
|
||||
return setmetatable(self, Span)
|
||||
end
|
||||
|
||||
function Span:set_attribute(k, v)
|
||||
table.insert(self.attributes, { key = k, value = v })
|
||||
return self
|
||||
end
|
||||
|
||||
function Span:end_span()
|
||||
self.end_time = time.now()
|
||||
self.tracer.processor:add(self)
|
||||
end
|
||||
|
||||
function Span:encode()
|
||||
return {
|
||||
trace_id = self.trace_id,
|
||||
span_id = self.span_id,
|
||||
parent_span_id = self.parent_context and self.parent_context.span_id,
|
||||
name = self.name,
|
||||
start_time_unix_nano = to_nanoseconds(self.start_time),
|
||||
end_time_unix_nano = to_nanoseconds(self.end_time),
|
||||
attributes = self.attributes,
|
||||
kind = self.kind or SpanKind.INTERNAL,
|
||||
status = {
|
||||
code = self.status or SpanStatus.OK
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
--------------------------------------------------
|
||||
-- Processor --
|
||||
--------------------------------------------------
|
||||
|
||||
local Processor = {}
|
||||
Processor.__index = Processor
|
||||
m.Processor = Processor
|
||||
|
||||
function Processor.new(exporter)
|
||||
local self = {
|
||||
exporter = exporter
|
||||
}
|
||||
return setmetatable(self, Processor)
|
||||
end
|
||||
|
||||
function Processor:add(span)
|
||||
self.exporter:export({ span })
|
||||
end
|
||||
|
||||
--------------------------------------------------
|
||||
-- Exporter --
|
||||
--------------------------------------------------
|
||||
|
||||
local Exporter = {}
|
||||
Exporter.__index = Exporter
|
||||
m.Exporter = Exporter
|
||||
|
||||
function Exporter.new(request_fn, endpoint)
|
||||
local self = {
|
||||
request_fn = request_fn,
|
||||
endpoint = endpoint,
|
||||
}
|
||||
return setmetatable(self, Exporter)
|
||||
end
|
||||
|
||||
function Exporter:export(spans)
|
||||
local body = {
|
||||
resource_spans = {
|
||||
{
|
||||
resource = spans[1].tracer.resource,
|
||||
scope_spans = {
|
||||
{
|
||||
scope = {
|
||||
name = spans[1].tracer.name,
|
||||
},
|
||||
spans = {}
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for _, span in ipairs(spans) do
|
||||
table.insert(
|
||||
body.resource_spans[1].scope_spans[1].spans,
|
||||
span:encode()
|
||||
)
|
||||
end
|
||||
|
||||
self.request_fn(
|
||||
self.endpoint, {
|
||||
method = "POST",
|
||||
headers = {
|
||||
["Content-Type"] = "application/json",
|
||||
},
|
||||
body = json.encode(body),
|
||||
},
|
||||
function(body, code, response)
|
||||
if code ~= 200 then
|
||||
module:log("error", json.encode(body))
|
||||
end
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
--------------------------------------------------
|
||||
-- Tracer --
|
||||
--------------------------------------------------
|
||||
|
||||
local Tracer = {}
|
||||
Tracer.__index = Tracer
|
||||
m.Tracer = Tracer
|
||||
|
||||
function Tracer.new(processor, service, name)
|
||||
return setmetatable({
|
||||
processor = processor,
|
||||
resource = {
|
||||
attributes = {
|
||||
{
|
||||
key = "service.name",
|
||||
value = Attribute.string(service)
|
||||
}
|
||||
}
|
||||
},
|
||||
name = name,
|
||||
}, Tracer)
|
||||
end
|
||||
|
||||
function Tracer:start_span(name, context)
|
||||
return Span.new(name, self, { context = context })
|
||||
end
|
||||
|
||||
return m
|
||||
Reference in New Issue
Block a user