0

I'm trying to get status code from response application and send it to external api bit in access_by_lua_file ngx.status or ngx.var.status always return 0 or 000. I use log_by_lua_file and get status code as my response application but I can't send it to external api because the API function is disabled is there another way to get status code and send it to external api

this my example code

logging.lua

local request_time = ngx.now() - ngx.req.start_time()
local data = {
    request_method = ngx.var.request_method,
    user_agent = ngx.var.http_user_agent,
    request_time = request_time,
    status = ngx.var.status,
    url = "http://" .. ngx.var.host .. ngx.var.request_uri,
    ip = ngx.var.remote_addr,
    time = ngx.var.time_iso8601,
    path = ngx.var.request_uri
}

local httpc = require("resty.http").new()
local output = cjson.encode(data)
ngx.log(ngx.ERR, ngx.status, ngx.var.status)
ngx.ctx.status_code = ngx.var.status
ngx.ctx.request_method = ngx.var.request_method
ngx.ctx.user_agent = ngx.var.user_agent
ngx.ctx.request_time = ngx.var.request_time
ngx.ctx.url = "http://" .. ngx.var.host .. ngx.var.request_uri
ngx.ctx.ip = ngx.var.remote_addr

-- ngx.location.capture("http://127.0.0.1:3232/api/create-log", { method = ngx.HTTP_POST, body = output })
-- ngx.location.capture_multi({"http://127.0.0.1:3232/api/create-log", { method = "POST", body = output}})

ngx.log(ngx.ERR, "dasdsadas ", ngx.var.status, " ", ngx.status, " ", ngx.var.upstream_status)

local res, err = httpc:request_uri("http://127.0.0.1:3232/api/create-log", {
    method = "POST",
    body = output,                    
    headers = {
        ["Content-Type"] = "application/json",
    },
})


if not res then
    ngx.log(ngx.ERR, "request failed: ", err)
end

nginx.conf

worker_processes auto;
events {
    worker_connections 1024;
}

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    default_type application/octet-stream;

    log_format json_output '{"time_local": "$time_local", '
        '"path": "$request_uri", '
        '"url": "http://$host$request_uri",'
        '"ip": "$remote_addr", '
        '"time": "$time_iso8601", '
        '"user_agent": "$http_user_agent", '
        '"user_id_got": "$uid_got", '
        '"user_id_set": "$uid_set", '
        '"remote_user": "$remote_user", '
        '"request": "$request", '
        '"status": "$status", '
        '"body_bytes_sent": "$body_bytes_sent", '
        '"request_time": "$request_time", '
        '"request_method": "$request_method",'
        '"http_referrer": "$http_referer" }';

    
    init_by_lua_block {
        cjson = require("cjson")
    }
    error_log logs/error.log error;

    server {
        listen 8080;
        access_log logs/access2.log json_output;

        location /hello {
            add_header Access-Control-Allow-Headers "Content-Type, Authorization, X-Requested-With, Cache-Control, Accept, Origin, X-Session-ID, Host";
            add_header Access-Control-Allow-Methods "OPTIONS, GET, POST, PUT, HEAD, DELETE, OPTIONS, TRACE, CONNECT";
            add_header Access-Control-Allow-Origin "*";

            if ($request_method = OPTIONS) {
                return 200;
            }

            if ($request_method = HEAD) {
                return 200;
            }

            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $host;
            proxy_set_header Connection "upgrade";
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            access_by_lua_file lua/logging.lua;
            proxy_pass http://127.0.0.1:3131;
        }

        location = /favicon.ico {
            log_not_found off;
        }
    }
}

1 Answers1

0

access_by_lua runs before the request is initiated to your upstream. Hence, the status codes won't be set and would be defaulted to 0. https://stackoverflow.com/a/62202290/9090571

The response & its status code is available in content_by_lua, header_filter_by_lua, body_filter_by_lua, or log_by_lua but you won't be able to directly initiate a httpc request because the API function is disabled.

There is a known workaround that I have used earlier using https://github.com/openresty/lua-nginx-module#ngxtimerat

local function push_data(request_method, http_user_agent, status, full_uri, args, remote_addr, time_iso8601, request_uri,request_time)
    local data = {
        request_method = request_method,
        user_agent = http_user_agent,
        status = status,
        full_uri = full_uri,
        args = args,
        ip = remote_addr,
        time = time_iso8601,
        path = request_uri,
        request_time = request_time,
    }

    local cjson = require "cjson"
    local output = cjson.encode(data)

    local httpc = require("/usr/local/openresty/nginx/resty/http").new()
    local res, err = httpc:request_uri("http://127.0.0.1:3232/api/create-log", {
        method = "POST",
        body = output,
        headers = {
            ["Content-Type"] = "application/json",
        },
    })

    if not res then
        ngx.log(ngx.ERR, "request failed: ", err)
    end
end

local ok, err = ngx.timer.at(0, push_data,
        ngx.var.request_method,
        ngx.var.http_user_agent,
        ngx.var.status,
        "http://" .. ngx.var.host .. ngx.var.uri,
        ngx.var.args,
        ngx.var.remote_addr,
        ngx.var.time_iso8601,
        ngx.var.request_uri,
        ngx.now() - ngx.req.start_time()
        -- any other variables you need to set
)
if not ok then
    ngx.log(ngx.ERR, "failed to create timer: ", err)
    return
end

Or, you could also use https://github.com/cloudflare/lua-resty-logger-socket although it is probably not maintained and has a bunch of open issues.