The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

NewRelic::Agent::FFI::Procedural - (Deprecated) Procedural interface for NewRelic APM

VERSION

version 0.10

SYNOPSIS

 use NewRelic::Agent::FFI::Procedural;
 
 # enable embedded mode:
 newrelic_register_message_handler newrelic_message_handler;
 
 # initialize:
 newrelic_init
   'abc123'     # license key
   'REST API'   # app name
 ;
 
 # use it:
 my $tx = newrelic_transaction_begin;
 ...
 my $rc = newrelic_transaction_end $tx;

DESCRIPTION

NOTE: This module is deprecated. It is based on the NewRelic Agent SDK, which was only ever released as beta software. Please use NewFangle instead.

This module provides bindings for the NewRelic Agent SDK.

Unlike NewRelic::Agent::FFI, this is NOT a drop in replacement for NewRelic::Agent. The author believes this interface is better. In addition to the reasons the author believes NewRelic::Agent::FFI to be better than NewRelic::Agent (listed in the former's documentation), the author believes this module to be better than NewRelic::Agent::FFI because:

Object oriented interface does represent or add anything

The NewRelic::Agent instance that you create doesn't represent anything in the NewRelic Agent SDK. In fact if you don't understand how things work under the hood, you might be confused into believing that you can initialize multiple agent instances in the same process.

Object oriented interface is slower

Because the unused $agent instance needs to be shifted off the stack before calling the underlying C code there is a lot more overhead in the object oriented interface.

Functions aren't renamed

The object oriented version renames a number of its methods, so translating C/C++ example code is nearly impossible. The procedural version uses the same function name and constants, so translating example code from other languages is easy.

API is complete

This interface is more complete than the object oriented version.

FUNCTIONS

All functions are exported by default. You can explicitly specify just the functions that you want in the usual Exporter way if you prefer.

Functions that return a $rc will return one of these codes (NEWRELIC_RETURN_CODE_OK is 0, the others are negative values):

NEWRELIC_RETURN_CODE_OK
NEWRELIC_RETURN_CODE_OTHER
NEWRELIC_RETURN_CODE_DISABLED
NEWRELIC_RETURN_CODE_INVALID_PARAM
NEWRELIC_RETURN_CODE_INVALID_ID
NEWRELIC_RETURN_CODE_TRANSACTION_NOT_STARTED
NEWRELIC_RETURN_CODE_TRANSACTION_IN_PROGRESS
NEWRELIC_RETURN_CODE_TRANSACTION_NOT_NAMED

Functions that return a $tx will return a transaction id on success, and a (negative) $rc code on failure.

Functions that return a $seg will return a segment id on success, and a (negative) $rc code on failure.

Functions that return a $address are the address to a C function that can be passed to other newrelic_ functions as appropriate.

For functions that take a $parent_seg argument, you can pass in NEWRELIC_AUTOSCOPE or NEWRELIC_ROOT_SEGMENT instead of a literal segment id.

For functions that take a $tx argument, you can pass in NEWRELIC_AUTOSCOPE instead of a literal transaction id.

newrelic_init

 my $rc = newrelic_init $license_key, $app_name, $app_language, $app_language_version;

Initialize the connection to NewRelic.

$license_key

A valid NewRelic license key for your account.

This value is also automatically sourced from the NEWRELIC_LICENSE_KEY environment variable.

$app_name

The name of your application.

This value is also automatically sourced from the NEWRELIC_APP_NAME environment variable.

$app_language

The language that your application is written in.

This value defaults to perl, and can also be automatically sourced from the NEWRELIC_APP_LANGUAGE environment variable.

$app_language_version

The version of the language that your application is written in.

This value defaults to your perl version, and can also be automatically sourced from the NEWRELIC_APP_LANGUAGE_VERSION environment variable.

newrelic_transaction_begin

 my $tx = newrelic_transaction_begin;

Identifies the beginning of a transaction, which is a timed operation consisting of multiple segments. By default, transaction type is set to WebTransaction and transaction category is set to Uri.

Returns the transaction's ID on success, else negative warning code or error code.

newrelic_transaction_set_name

 my $rc = newrelic_transaction_set_name $tx, $name;

Sets the transaction name.

newrelic_transaction_set_request_url

 my $rc = newrelic_transaction_set_request_url $tx, $url;

Sets the transaction URL.

newrelic_transaction_set_max_trace_segments

 my $rc = newrelic_transaction_set_max_trace_segments $tx, $max;

Sets the maximum trace section for the transaction.

newrelic_transaction_set_category

 my $rc = newrelic_transaction_set_category $tx, $category;

Sets the transaction category.

newrelic_transaction_set_type_web

 my $rc = newrelic_transaction_set_type_web $tx;

Sets the transaction type to 'web'

newrelic_transaction_set_type_other

 my $rc = newrelic_transaction_set_type_other $tx;

Sets the transaction type to 'other'

newrelic_transaction_add_attribute

 my $rc = newrelic_transaction_add_attribute $tx, $key => $value;

Adds the given attribute (key/value pair) for the transaction.

newrelic_transaction_notice_error

 my $rc = newrelic_transaction_notice_error $tx, $exception_type, $error_message, $stack_trace, $stack_frame_delimiter;

Identify an error that occurred during the transaction. The first identified error is sent with each transaction.

newrelic_transaction_end

 my $rc = newrelic_transaction_end $tx;

newrelic_record_metric

 my $rc = newrelic_record_metric $key => $value;

Records the given metric (key/value pair). The $value should be a floating point.

newrelic_record_cpu_usage

 my $rc = newrelic_record_cpu_usage $cpu_user_time_seconds, $cpu_usage_percent;

Records the CPU usage. $cpu_user_time_seconds and $cpu_usage_percent are floating point values.

newrelic_record_memory_usage

 my $rc = newrelic_record_memory_usage $memory_megabytes;

Records the memory usage. $memory_megabytes is a floating point value.

newrelic_segment_generic_begin

 my $seg = newrelic_segment_generic_begin $tx, $parent_seg, $name;

Begins a new generic segment. $parent_seg is a parent segment id (undef no parent). $name is a string.

newrelic_segment_datastore_begin

 my $seg = newrelic_segment_datastore_begin $tx, $parent_seg, $table, $operation, $sql, $sql_trace_rollup_name;
 my $seg = newrelic_segment_datastore_begin $tx, $parent_seg, $table, $operation, $sql, $sql_trace_rollup_name, $sql_obfuscator;

Begins a new datastore segment. $parent_seg is a parent segment id (undef no parent). $operation should be one of select, insert, update or delete.

If you want to provide your own obfuscator, you need to pass in the address of a C function. To do that from Perl you can create a closure with FFI::Platypus, like so:

 use 5.010;
 use FFI::Platypus;
 use FFI::Platypus::Memory qw( strdup free );
 
 sub myobfuscator
 {
   # input SQL
   my($sql) = @_;
 
   # make some kind of transformation
   $sql =~ tr/a-z/z-a/;
 
   # because C has a different ownership model than Perl for functions
   # that return a string, you need to create a C pointer to a copy of
   # the return value.  On the next call we will free the previous copy.
   state $ptr = 0;
   free($ptr) if $ptr;
   return $ptr = strdup($sql);
 }
 
 $ffi->type('(string)->opaque' => 'obfuscator_t');
 my $myobfuscator_closure = $ffi->closure(\&myobfuscator);
 my $myobfuscator_ptr     = $ffi->cast('obfuscator_t' => 'opaque', $myobfuscator_closure);
 
 newrelic_segment_datastore_begin $tx, $seg, $table, $sql, $rollup, $myobfuscator_ptr;
 ...

newrelic_segment_external_begin

 my $seg = newrelic_segment_external_begin $tx, $parent_seg, $host, $name;

Begins a new external segment. $parent_seg is a parent segment id (undef no parent).

newrelic_segment_end

 my $rc = newrelic_segment_end $tx, $seg;

End the given segment.

newrelic_register_message_handler

 newrelic_register_message_handler $handler;

Register the message handler used to send messages to NewRelic. The only useful way at the moment to use this function is by giving it newrelic_message_handler, which sends messages directly to NewRelic, rather than through a separate daemon process:

 newrelic_register_message_handler newrelic_message_handler;

This needs to be called BEFORE you call newrelic_init.

newrelic_message_handler

 my $address = newrelic_message_handler;

Returns the address of the C function that handles sending messages directly to NewRelic. This cannot be called directly from Perl, but can be passed to newrelic_register_message_handler like so:

 newrelic_register_message_handler newrelic_message_handler;

This needs to be called BEFORE you call newrelic_init.

newrelic_basic_literal_replacement_obfuscator

 my $address = newrelic_basic_literal_replacement_obfuscator;

Returns the address of the C function that does the basic/default obfuscator contained within the NewRelic agent library. Normally you wouldn't call this from Perl, so it is the address of the function, not the function itself. You can, however, call it via FFI::Platypus:

 use FFI::Platypus;
 
 my $ffi = FFI::Platypus->new;
 $new->attach( newrelic_basic_literal_replacement_obfuscator, ['string'] => 'string');
 my $save = newrelic_basic_literal_replacement_obfuscator("SELECT * FROM user WHERE password = 'secret'");

newrelic_request_shutdown

 my $rc = newrelic_request_shutdown $reason;

Tell the Collector Client to shutdown and stop reporting application performance data to New Relic.

newrelic_enable_instrumentation

 newrelic_enable_instrumentation $set_enabled;

Disable/enable instrumentation. By default, instrumentation is enabled.

$set_enabled 0 to disable, 1 to enable

CAVEATS

Platform Limitations

The SDK binaries provided by New Relic only work on Linux x86_64. The binaries are labeled as a "beta" and were released in July 2016. It doesn't seem likely that New Relic will be releasing new versions of the SDK. The author of this module has had good success getting this module to work on Ubuntu Precise and Xenial, and heard from user feedback that it works with Bionic. I have heard that it does NOT work with CentOS 7. Your mileage may vary.

Not Fork Safe!

Bad things will happen if you call newrelic_init before forking. So don't do that.

SEE ALSO

NewRelic::Agent::FFI

AUTHOR

Author: Graham Ollis <plicease@cpan.org>

Contributors:

Ville Skyttä (SCOP)

COPYRIGHT AND LICENSE

This software is copyright (c) 2018 by Graham Ollis.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.