Skip to content

danifbento/lua-newrelic-integration

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

20 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

lua-newrelic-integration

Lua Newrelic SDK for the ngx_lua based on New Relic C SDK.

New Relic One is a powerful full-stack data analysis platform for all your software's metrics, events, and logs. Now available with a modern, consumption pricing model. Explore the platform Get free access. Platform Capabilities AIOps Alerts Application Monitoring (APM) Browser Monitoring ...

Build Status

Table of Contents

Status

This library is being tested. By default SDK will send all data using SSL.

This library transposes all methods from C-SDK into Lua. It is based on the original lua-resty-newrelic from Aliaksandr "saksmlz" Rahalevich <saksmlz__at__gmail.com>.

Description

This Lua library is a luajit ffi-based wrapper around newrelic C-SDK for the ngx_lua nginx module.

Please read newrelic C-SDK Documentation for more details on each function/method.

This library can only be used with luajit, NOT lua, because uses luajit ffi.

Synopsis

    http {
        # you do not need the following line if you are using
        # the OpenResty bundle:
        lua_package_path "/path/to/nri-newrelic/lib/?.lua;;";

        env NEWRELIC_APP_LICENSE_KEY=<your newrelic lincense key>;
        env NEWRELIC_APP_NAME=<your newrelic application name>;

        init_worker_by_lua_block {
            local newrelic_agent = require("lua-nri.newrelic_agent")
                configuration = {
                    log = {
                        enabled  = true,
                        filename = "logs/newrelic.log",
                        level    = newrelic_agent.consts.NEWRELIC_LOG_DEBUG,
                    }
                }
                newrelic_agent.enable(configuration)
        }

        server {
            location /test {
                rewrite_by_lua_block {
                    require('lua-nri.newrelic_agent').start_web_transaction()
                }

                # here you can use any directive that generates response body like: try_files,
                # proxy_pass, content_by_lua_*, etc.
                content_by_lua_block {
                    local newrelic_agent = require 'lua-nri.newrelic_agent'

                    local call_remote_host = function(uri)
                      ngx.log(ngx.ERR, 'Calling ' .. uri .. ' host...')
                      ngx.sleep(math.random())
                    end

                    local redis = require 'resty.redis'
                    local red = redis:new()
                    red:set_timeout(math.random(1000))

                    -- track database query
                    local redis_connect_segment_id = newrelic_agent.start_datastore_segment(
                        newrelic_agent.consts.NEWRELIC_DATASTORE_REDIS,
                        "Collection",
                        "GET",
                        "127.0.0.1",
                        "6379",
                        "database_name",
                        ""
                    )

                    local connect_ok, connect_err = red:connect('127.0.0.1', 6379)
                    newrelic_agent.end_segment(redis_connect_segment_id)

                    -- increment custom metric
                    if connect_ok then
                      newrelic_agent.record_custom_metric('redis_client/new_connect', 1)
                    else
                      -- log error to newrelic
                      newrelic_agent.notice_error('Failed to connect to redis', connect_err, debug.traceback(), '\n')
                    end

                    -- segment and sub_segment
                    local hello_segment_id = newrelic_agent.start_segment('hello', 'teste')
                    ngx.say('hello')

                    newrelic_agent.set_segment_timing(hello_segment_id, 1000)
                    local hello_sub_segment_id = newrelic_agent.start_segment('hello_sub_segment', 'teste')
                    newrelic_agent.set_segment_parent(hello_sub_segment_id, hello_segment_id)
                    -- create and accept distributed trace payload
                    local dt = newrelic_agent.create_distributed_trace_payload(hello_segment_id)
                    newrelic_agent.accept_distributed_trace_payload("payload", newrelic_agent.NEWRELIC_TRANSPORT_TYPE_HTTP)

                    newrelic_agent.end_segment(hello_sub_segment_id)
                    newrelic_agent.end_segment(hello_segment_id)

                    -- track remote call
                    local uri = 'http://google.com'
                    local external_segment_id = newrelic_agent.start_external_segment(uri, 'google home page', 'library')
                    call_remote_host(uri)
                    newrelic_agent.end_segment(external_segment_id)

                    -- add a custom event
                    local custom_event = newrelic_agent.custom_event("NewCustomEvent")
                    newrelic_agent.custom_event_add_attribute(custom_event, "give_int", 200)
                    newrelic_agent.custom_event_add_attribute(custom_event, "give_long", 2147483650)
                    newrelic_agent.custom_event_add_attribute(custom_event, "give_double", 1.0)
                    newrelic_agent.custom_event_add_attribute(custom_event, "give_string", "string_to_check_string")
                    newrelic_agent.record_custom_event(custom_event)

                    -- start/end a non web transction
                    newrelic_agent.start_non_web_transaction(ngx.var.uri .. "-non-web")
                    newrelic_agent.end_non_web_transaction()

                    -- set transaction properties
                    newrelic_agent.set_transaction_name("NewTransactionName")
                    newrelic_agent.set_transaction_timing(1000)

                }

                log_by_lua_block {
                    local newrelic_agent = require("lua-nri.newrelic_agent")
                    newrelic_agent.end_web_transaction()
                }
            }
        }
    }

API

enable - enable the newrelic lua client

  • configuration: an object with all configuration fields
enable(configuration)

notice_error - add an error to the current transaction

  • priority: the priority of the error, the higher one will be reported to newrelic
  • message : the error message
  • class : the error class
notice_error(priority, message, class)

start_web_transaction - start new web transaction (it creates the id under ngx.ctx.nr_transaction_id)

start_web_transaction()

end_web_transaction - end the current web transaction

end_web_transaction()

start_segment - start a new segment inside the transaction

  • name : the name of the segment
  • category : the category of the segment
start_segment(name, category)

end_segment - end a given segment

end_segment(segment_id)

start_non_web_transaction - start a new non web transaction (it creates the id under ngx.ctx.nr_transaction_id_non_web)

start_non_web_transaction(name)

end_non_web_transaction - end a non web transaction

end_non_web_transaction()

ignore_transaction - ignores the current transaction

ignore_transaction()

add_attribute - add an attribute to the current transaction (it maps for int, long, double and string)

  • name : the name of the attribute
  • value: the value of the attribute
add_attribute(name, value)

custom_event - create a custom event

  • type: type of the event
custom_event(type)

record_custom_event - prepare event to be sent to New Relic, without this, the custom event is not sent

  • event: the event to be recorded
record_custom_event(event)

discard_custom_event - discard the given custom event

  • event: the event to be discarded
discard_custom_event(event)

custom_event_add_attribute - add an attribute to the custom event (it maps for int, long, double and string)

  • custom_event: the event to attach the attribute
  • name : the name of the attribute
  • value : the value of the attribute
custom_event_add_attribute(custom_event, name, value)

record_custom_metric - record a custom metric

  • name : name of the metric
  • milliseconds: time duration to record
record_custom_metric(name, milliseconds)

start_datastore_segment - start a datastore segment

  • product :
  • collection : the collection of data
  • operation : the operation being performed
  • host : the host which receives the connection
  • port_or_path_id: the port of the host
  • database_name : the database_name
  • query : the performed query
start_datastore_segment(product, collection, operation, host, port_or_path_id, database_name, query)

start_external_segment - start a external segment

  • uri : the uri of the segment
  • procedure: the procedure being executed
  • library : the library being used
start_external_segment(uri, procedure, library)

set_transaction_name - override current transaction name

  • name: new name for the transaction
set_transaction_name(name)

set_transaction_timing - override current transaction time

  • duration : duration of the transacion
  • start_time: begin of the transaction (if nil, it will use ngx.time())
set_transaction_timing(duration, start_time)

set_transaction_timing - override current segment time

  • segment : segmetn to be override
  • duration : duration of the segment
  • start_time: begin of the segment (if nil, it will use ngx.time())
set_segment_timing(segment, duration, start_time)

set_segment_parent_root - set segment as root

  • segment: segment to be rooted
set_segment_parent_root(segment)

set_segment_parent - set a new parent for a given segment

  • segment : segment to be parented
  • parent_segment: the parent segment
set_segment_parent(segment, parent_segment)

create_distributed_trace_payload - create a trace payload

  • payload : the payload to be sent
  • transport_type: the transport type (given by constants)
create_distributed_trace_payload(payload, transport_type)

create_distributed_trace_payload_httpsafe - create a httpsafe trace payload

  • payload : the payload to be sent
  • transport_type: the transport type (given by constants)
create_distributed_trace_payload_httpsafe(payload, transport_type)

accept_distributed_trace_payload - accept a trace payload

  • payload : the payload to be sent
  • transport_type: the transport type (given by constants)
accept_distributed_trace_payload(payload, transport_type)

accept_distributed_trace_payload_httpsafe - accept a httpsafe trace payload

  • payload : the payload to be sent
  • transport_type: the transport type (given by constants)
accept_distributed_trace_payload_httpsafe(payload, transport_type)

Installation

Download and install http://github.com/newrelic/c-sdk following the instructions of the repository. You will get two artifacts after make on this repo:

  • newrelic_daemon
  • libnewrelic.a

You should run newrelic_daemon as:

$./newrelic_daemon -f --logfile stdout --loglevel debug

To get the *.so needed to run this library you need to:

$ ar -x libnewrelic.a
$ gcc -shared -lpcre -lm -lpthread -rdynamic *.o -o libnewrelic.so

And put libnewrelic.so on your LD_PATH

If you are using the OpenResty bundle (http://openresty.org ), then just download lua file newrelic.lua and newrelic_agent.lua files to the directiory where nginx will find it. Another way to install is to use luarocks running:

$ luarocks install lua-newrelic-integration

If you are using your own nginx + ngx_lua build, then you need to configure the lua_package_path directive to add the path of your lua-newrelic-integration source tree to ngx_lua's LUA_PATH search path, as in

    # nginx.conf
    http {
        lua_package_path "/path/to/lua-nri/lib/?.lua;;";
        ...
    }

Ensure that the system account running your Nginx ''worker'' proceses have enough permission to read the .lua file.

Back to TOC

Tested with

  • Linux
  • openresty 1.19.9.1
  • C-SDK 1.3.0

TODO

  • Add tests to each newrelic_agent/newrelic method
  • Improve README with case scenarios
  • Add examples
  • Add Travis CI

Bugs and Patches

Please report bugs or submit patches by

  1. creating a ticket on the GitHub Issue Tracker,

Back to TOC

Author

Daniela Filipe Bento (danifbento) [email protected].

Back to TOC