前天写了一个日志记录的插件,是将接口请求和返回的一些相关内容,以指定的数据格式写入到文件,方便大数据使用 Filebeat 读取,并显示在 ELK,话不多说上代码。

schema.lua

local typedefs = require "kong.db.schema.typedefs"

return {
  name = "file-log",
  fields = {
    { protocols = typedefs.protocols_http },
    { config = {
        type = "record",
        fields = {
          { path = { type = "string",
                 required = true,
                 match = [[^[^*&%%\`]+$]],
                 err = "not a valid filename",
          }, },
          { reopen = { type = "boolean", default = false }, },
    }, }, },
  }
}

handler.lua

local kong = kong
local ffi = require "ffi"
local zlib = require("zlib")
local cjson = require "cjson"
local concat = table.concat
local system_constants = require "lua_system_constants"

local O_CREAT = system_constants.O_CREAT()
local O_WRONLY = system_constants.O_WRONLY()
local O_APPEND = system_constants.O_APPEND()
local S_IRUSR = system_constants.S_IRUSR()
local S_IWUSR = system_constants.S_IWUSR()
local S_IRGRP = system_constants.S_IRGRP()
local S_IROTH = system_constants.S_IROTH()

local oflags = bit.bor(O_WRONLY, O_CREAT, O_APPEND)

local mode = bit.bor(S_IRUSR, S_IWUSR, S_IRGRP, S_IROTH)

local C = ffi.C

ffi.cdef [[
int write(int fd, const void * ptr, int numbytes);
]]

-- fd tracking utility functions
local file_descriptors = {}

local FileLogHandler = {}

FileLogHandler.PRIORITY = 9
FileLogHandler.VERSION = "2.0.1"

function FileLogHandler:access(conf)
    kong.ctx.shared.access_time = ngx.now()
end

function FileLogHandler:body_filter(conf)

    local ctx = ngx.ctx
    local chunk, eof = ngx.arg[1], ngx.arg[2]
    local uncompress

    ctx.rt_body_chunks = ctx.rt_body_chunks or {}
    ctx.rt_body_chunk_number = ctx.rt_body_chunk_number or 1

    if eof then
        local chunks = concat(ctx.rt_body_chunks)

        local encoding = kong.response.get_header("Content-Encoding")
        if encoding == "gzip" then
            uncompress = zlib.inflate()(chunks)
        end

        kong.ctx.shared.respbody = uncompress or chunks
        ngx.arg[1] = chunks
    else
        ctx.rt_body_chunks[ctx.rt_body_chunk_number] = chunk
        ctx.rt_body_chunk_number = ctx.rt_body_chunk_number + 1
        ngx.arg[1] = nil
    end
end

function FileLogHandler:log(conf)
    -- local message = serialize(ngx)
    local data

    data = ngx.req.get_body_data()

    local logs = {
        client_ip = kong.client.get_ip(),
        client_forwarded_ip = kong.client.get_forwarded_ip(),
        request_scheme = kong.request.get_scheme(),
        request_host = kong.request.get_host(),
        request_method = kong.request.get_method(),
        request_path = kong.request.get_path(),
        request_headers = kong.request.get_headers(),
        request_sunmi_id = kong.ctx.shared.sunmi_id,
        request_sunmi_shopid = kong.ctx.shared.sunmi_shopid,
        request_raw_body = data,
        response_status = kong.response.get_status(),
        response_headers = kong.response.get_headers(),
        response_body = kong.ctx.shared.respbody,
        process_time = 0,
        time = 0
    }

    if kong.ctx.shared.access_time ~= nil then
        logs.process_time = (ngx.now() - kong.ctx.shared.access_time)
        logs.time = kong.ctx.shared.access_time
    end

    local msg = cjson.encode(logs) .. "\n"

    local fd = file_descriptors[conf.path]

    if fd and conf.reopen then
        C.close(fd)
        file_descriptors[conf.path] = nil
        fd = nil
    end

    if not fd then
        fd = C.open(conf.path, oflags, mode)
        if fd < 0 then
            local errno = ffi.errno()
            ngx.log(ngx.ERR, "[file-log] failed to open the file: ", ffi.string(C.strerror(errno)))
        else
            file_descriptors[conf.path] = fd
        end
    end

    C.write(fd, msg, #msg)

end

return FileLogHandler

如下图,设置路径开启后,请求相关的信息会写入到你设置的路径文件中。
log plugins

最后修改:2020 年 07 月 16 日 04 : 39 PM
如果觉得我的文章对你有用,请随意赞赏