Skip to content

Commit

Permalink
working implementation of loggly plugin
Browse files Browse the repository at this point in the history
Signed-off-by: Bisakh Mondal <bisakhmondal00@gmail.com>
  • Loading branch information
bisakhmondal committed Jan 14, 2022
1 parent 2a67374 commit 0369500
Show file tree
Hide file tree
Showing 4 changed files with 234 additions and 1 deletion.
228 changes: 228 additions & 0 deletions apisix/plugins/loggly.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
--
-- Licensed to the Apache Software Foundation (ASF) under one or more
-- contributor license agreements. See the NOTICE file distributed with
-- this work for additional information regarding copyright ownership.
-- The ASF licenses this file to You under the Apache License, Version 2.0
-- (the "License"); you may not use this file except in compliance with
-- the License. You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
local core = require("apisix.core")
local plugin = require("apisix.plugin")
local bp_manager_mod = require("apisix.utils.batch-processor-manager")
local log_util = require("apisix.utils.log-util")
local severity = require("apisix.plugins.slslog.rfc5424").severity
local service_fetch = require("apisix.http.service").get
local ngx = ngx
local tostring = tostring
local tab_concat = table.concat
local udp = ngx.socket.udp

local plugin_name = "loggly"
local batch_processor_manager = bp_manager_mod.new(plugin_name)

local schema = {
type = "object",
properties = {
customer_token = {type = "string"},
severity = {
type = "string",
default = "INFO",
enum = {"DEBUG", "INFO", "NOTICE", "WARNING", "ERR", "CRIT", "ALERT", "EMEGR"},
description = "base severity log level",
},
include_req_body = {type = "boolean", default = false},
tags = {
type = "array",
minItems = 1,
items = {
type = "string"
}
},
prefer_name = {type = "boolean", default = true}
},
required = {"customer_token"}
}


local defaults = {
host = "logs-01.loggly.com",
port = 514,
protocol = "syslog",
timeout = 5000
}

local metadata_schema = {
type = "object",
properties = {
host = {
type = "string",
default = defaults.host
},
port = {
type = "integer",
default = defaults.port
},
protocol = {
type = "string",
default = defaults.protocol,
-- more methods coming soon
enum = {"syslog"}
},
timeout = {
type = "integer",
minimum = 1,
default= defaults.timeout
},
}
}

local _M = {
version = 0.1,
priority = 411,
name = plugin_name,
schema = batch_processor_manager:wrap_schema(schema),
metadata_schema = metadata_schema
}

function _M.check_schema(conf, schema_type)
if schema_type == core.schema.TYPE_METADATA then
return core.schema.check(metadata_schema, conf)
end
local ok, err = core.schema.check(schema, conf)
if not ok then
return false, err
end
if conf.tags then
for i = 1, #conf.tags do
if not conf.tags[i]:sub(1, 4) ~= "tag=" then
conf.tags[i] = "tag=\"" .. conf.tags[i] .. "\""
end
end
end

return true
end

local function generate_log_message(conf, ctx)
local entry = log_util.get_full_log(ngx, {
include_req_body = conf.include_req_body
})
entry.latency, entry.upstream_latency,
entry.apisix_latency = log_util.latency_details_in_ms(ctx)

if conf.prefer_name then
if entry.service_id and entry.service_id ~= "" then
local svc = service_fetch(entry.service_id)

if svc and svc.value.name ~= "" then
entry.service_id = svc.value.name
end
end

if ctx.route_name and ctx.route_name ~= "" then
entry.route_id = ctx.route_name
end
end

-- generate rfc5424 compliant syslog event
local json_str, err = core.json.encode(entry)
if not json_str then
core.log.error('error occurred while encoding the data: ', err)
return nil
end

local timestamp = log_util.get_rfc3339_zulu_timestamp()
local taglist = ""
if conf.tags then
taglist = tab_concat(conf.tags, " ")
end
local message = {
-- facility LOG_USER - random user level message
"<".. tostring(8 + severity[conf.severity]) .. ">1", -- <PRIVAL>1
timestamp, -- timestamp
ctx.var.host or "-", -- hostname
"apisix", -- appname
ctx.var.pid, -- proc-id
"-", -- msgid
"[" .. conf.customer_token .. "@41058 " .. taglist .. "]",
json_str
}

return tab_concat(message, " ")
end

local function send_data_over_udp(message)
local metadata = plugin.plugin_metadata(plugin_name)
if not metadata then
core.log.info("received nil metadata: using metadata defaults: ",
core.json.delay_encode(defaults, true))
metadata = {}
metadata.value = defaults
end
local err_msg
local res = true
local sock = udp()
local host, port = metadata.value.host, metadata.value.port
sock:settimeout(metadata.value.timeout)

core.log.info("sending a batch logs to ", host, ":", port)

local ok, err = sock:setpeername(host, port)

if not ok then
return false, "failed to connect to UDP server: host[" .. host
.. "] port[" .. tostring(port) .. "] err: " .. err
end

ok, err = sock:send(message)
if not ok then
res = false
err_msg = "failed to send data to UDP server: host[" .. host
.. "] port[" .. tostring(port) .. "] err:" .. err
end

ok, err = sock:close()
if not ok then
core.log.error("failed to close the UDP connection, host[",
host, "] port[", port, "] ", err)
end

return res, err_msg
end

local function handle_log(entries, batch_max_size)
local data, err
if batch_max_size == 1 then
data, err = core.json.encode(entries[1]) -- encode as single {}
else
data, err = core.json.encode(entries) -- encode as array [{}]
end

if not data then
return false, 'error occurred while encoding the data: ' .. err
end
return send_data_over_udp(data)
end

function _M.log(conf, ctx)
local log_data = generate_log_message(conf, ctx)
if not log_data then
return
end

if batch_processor_manager:add_entry(conf, log_data) then
return
end

batch_processor_manager:add_entry_to_new_processor(conf, log_data, ctx, handle_log)
end

return _M
5 changes: 4 additions & 1 deletion apisix/plugins/slslog/rfc5424.lua
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,10 @@ local Severity = {
local log_util = require("apisix.utils.log-util")


local _M = { version = 0.1 }
local _M = {
version = 0.1,
severity = Severity
}

function _M.encode(facility, severity, hostname, appname, pid, project,
logstore, access_key_id, access_key_secret, msg)
Expand Down
1 change: 1 addition & 0 deletions conf/config-default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,7 @@ plugins: # plugin list (sorted by priority)
- prometheus # priority: 500
- datadog # priority: 495
- echo # priority: 412
- loggly # priority: 411
- http-logger # priority: 410
- splunk-hec-logging # priority: 409
- skywalking-logger # priority: 408
Expand Down
1 change: 1 addition & 0 deletions t/admin/plugins.t
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ grpc-web
prometheus
datadog
echo
loggly
http-logger
splunk-hec-logging
skywalking-logger
Expand Down

0 comments on commit 0369500

Please sign in to comment.