grthtrhthjhtyjytjytkergtrhtrjytjerhrfh4:24 29/09/2026-- vim: st=4 sts=4 sw=4 et: --- Utility functions module. -- This is mostly used for internal stuff and should not be relevant for end -- users (except some function that can be overridden). -- -- @module raven.util -- @copyright 2014-2017 CloudFlare, Inc. -- @license BSD 3-clause (see LICENSE file) local string_format = string.format local string_find = string.find local string_sub = string.sub local string_match = string.match local math_random = math.random local math_randomseed = math.randomseed local os_date = os.date local os_time = os.time local _M = {} local _VERSION = "0.5.0" _M._VERSION = _VERSION --- Used to log errors during reporting. -- The default implementation is quite dumb: it will simply use `print` to -- display the error message. Users are encouraged to override this -- implementation to something smarter. -- @param ... Message to log (will be concatenated) function _M.errlog(...) print("[ERROR]", ...) end -- Seed the random number generator math_randomseed(os_time()) --- Returns a string suitable to be used as `event_id`. -- @return a new random `event_id` string. function _M.generate_event_id() -- Some version of Lua can only generate random integers up to 2^31, so we are limited to 7 -- hex-digits per call return string_format("%07x%07x%07x%07x%04x", math_random(0, 0xfffffff), math_random(0, 0xfffffff), math_random(0, 0xfffffff), math_random(0, 0xfffffff), math_random(0, 0xffff)) end --- Returns the current date/time in ISO8601 format with no timezone indicator -- but in UTC. function _M.iso8601() -- The ! forces os_date to return UTC. Don't change this to use -- os.date/os.time to format the date/time because timezone -- problems occur local t = os_date("!*t") return string_format("%04d-%02d-%02dT%02d:%02d:%02d", t["year"], t["month"], t["day"], t["hour"], t["min"], t["sec"]) end local iso8601 = _M.iso8601 -- parse_host_port: parse long host ("127.0.0.1:2222") -- to host ("127.0.0.1") and port (2222) local function parse_host_port(protocol, host) local i = string_find(host, ":") if not i then return host, protocol == 'https' and 443 or 80 end local port_str = string_sub(host, i + 1) local port = tonumber(port_str) if not port then return nil, nil, "illegal port: " .. port_str end return string_sub(host, 1, i - 1), port end --- Parsed DSN table containing its different fields. -- @field protocol Connection protocol (`http`, `https`, ...) -- @field public_key -- @field secret_key -- @field host Hostname (without the port part) -- @field port Port to connect to as a number (always filled, default -- depend on protocol) -- @field path -- @field project_id -- @field request_uri URI path for storing messages -- @field server Full URL to the `/store/` Sentry endpoint -- @table parsed_dsn --- Parses a DSN and returns a table with parsed elements. -- @param dsn DSN to parse (string) -- @param[opt] obj Table to populate (create a new one if not provided) -- @return[1] populated table, see @{parsed_dsn} -- @return[2] nil -- @return[2] error message function _M.parse_dsn(dsn, obj) if not obj then obj = {} end assert(type(obj) == "table") -- '{PROTOCOL}://{PUBLIC_KEY}@{HOST}/{PATH}{PROJECT_ID}' obj.protocol, obj.public_key, obj.long_host, obj.path, obj.project_id = string_match(dsn, "^([^:]+)://([^:]+)@([^/]+)(.*/)(.+)$") if not obj.protocol then -- '{PROTOCOL}://{PUBLIC_KEY}:{SECRET_KEY}@{HOST}/{PATH}{PROJECT_ID}' obj.protocol, obj.public_key, obj.secret_key, obj.long_host, obj.path, obj.project_id = string_match(dsn, "^([^:]+)://([^:]+):([^@]+)@([^/]+)(.*/)(.+)$") end if obj.protocol and obj.public_key and obj.long_host and obj.project_id then local host, port, err = parse_host_port(obj.protocol, obj.long_host) if not host then return nil, err end obj.host = host obj.port = port obj.request_uri = string_format("%sapi/%s/store/", obj.path, obj.project_id) obj.server = string_format("%s://%s:%d%s", obj.protocol, obj.host, obj.port, obj.request_uri) return obj end return nil, "failed to parse DSN string" end --- Generate a Sentry compliant `X-Sentry-Auth` header value. -- @param dsn_object A @{parsed_dsn} table -- @return A Sentry authentication string function _M.generate_auth_header(dsn_object) if not dsn_object.secret_key then return string_format( "Sentry sentry_version=6, sentry_client=%s, sentry_timestamp=%s, sentry_key=%s", "raven-lua/" .. _VERSION, iso8601(), dsn_object.public_key) end return string_format( "Sentry sentry_version=6, sentry_client=%s, sentry_timestamp=%s, sentry_key=%s, sentry_secret=%s", "raven-lua/" .. _VERSION, iso8601(), dsn_object.public_key, dsn_object.secret_key) end return _M