Skip to content

Commit

Permalink
Merge pull request #38 from kneitinger/lumen_support
Browse files Browse the repository at this point in the history
Add Initial Laravel Lumen support.

Names transactions based off current route/controller, handles reports exceptions to NR
  • Loading branch information
kneitinger committed Dec 2, 2020
2 parents 9fec7d0 + 71b2b3a commit bab8316
Show file tree
Hide file tree
Showing 5 changed files with 214 additions and 2 deletions.
2 changes: 1 addition & 1 deletion agent/config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ if test "$PHP_NEWRELIC" = "yes"; then

dnl Actually define our extension, and far more importantly, its source
dnl files.
PHP_NEW_EXTENSION(newrelic, fw_cakephp.c fw_codeigniter.c fw_drupal8.c fw_drupal.c fw_drupal_common.c fw_joomla.c fw_kohana.c fw_laminas3.c fw_laravel.c fw_laravel_queue.c fw_magento1.c fw_magento2.c fw_magento_common.c fw_mediawiki.c fw_silex.c fw_slim.c fw_support.c fw_symfony4.c fw_symfony2.c fw_symfony.c fw_symfony_common.c fw_wordpress.c fw_yii.c fw_zend2.c fw_zend.c lib_doctrine2.c lib_guzzle3.c lib_guzzle4.c lib_guzzle6.c lib_guzzle_common.c lib_mongodb.c lib_phpunit.c lib_predis.c lib_zend_http.c php_agent.c php_api.c php_api_datastore.c php_api_distributed_trace.c php_api_internal.c php_autorum.c php_call.c php_curl.c php_curl_md.c php_datastore.c php_environment.c php_error.c php_execute.c php_explain.c php_explain_mysqli.c php_explain_pdo_mysql.c php_extension.c php_file_get_contents.c php_globals.c php_hash.c php_header.c php_httprequest_send.c php_internal_instrument.c php_minit.c php_mshutdown.c php_mysql.c php_mysqli.c php_newrelic.c php_nrini.c php_output.c php_pdo.c php_pdo_mysql.c php_pdo_pgsql.c php_pgsql.c php_psr7.c php_redis.c php_rinit.c php_rshutdown.c php_samplers.c php_stack.c php_stacked_segment.c php_txn.c php_user_instrument.c php_vm.c php_wrapper.c, $ext_shared,, \\$(NEWRELIC_CFLAGS))
PHP_NEW_EXTENSION(newrelic, fw_cakephp.c fw_codeigniter.c fw_drupal8.c fw_drupal.c fw_drupal_common.c fw_joomla.c fw_kohana.c fw_laminas3.c fw_laravel.c fw_laravel_queue.c fw_lumen.c fw_magento1.c fw_magento2.c fw_magento_common.c fw_mediawiki.c fw_silex.c fw_slim.c fw_support.c fw_symfony4.c fw_symfony2.c fw_symfony.c fw_symfony_common.c fw_wordpress.c fw_yii.c fw_zend2.c fw_zend.c lib_doctrine2.c lib_guzzle3.c lib_guzzle4.c lib_guzzle6.c lib_guzzle_common.c lib_mongodb.c lib_phpunit.c lib_predis.c lib_zend_http.c php_agent.c php_api.c php_api_datastore.c php_api_distributed_trace.c php_api_internal.c php_autorum.c php_call.c php_curl.c php_curl_md.c php_datastore.c php_environment.c php_error.c php_execute.c php_explain.c php_explain_mysqli.c php_explain_pdo_mysql.c php_extension.c php_file_get_contents.c php_globals.c php_hash.c php_header.c php_httprequest_send.c php_internal_instrument.c php_minit.c php_mshutdown.c php_mysql.c php_mysqli.c php_newrelic.c php_nrini.c php_output.c php_pdo.c php_pdo_mysql.c php_pdo_pgsql.c php_pgsql.c php_psr7.c php_redis.c php_rinit.c php_rshutdown.c php_samplers.c php_stack.c php_stacked_segment.c php_txn.c php_user_instrument.c php_vm.c php_wrapper.c, $ext_shared,, \\$(NEWRELIC_CFLAGS))

PHP_SUBST(NEWRELIC_CFLAGS)

Expand Down
1 change: 1 addition & 0 deletions agent/fw_hooks.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ extern void nr_joomla_enable(TSRMLS_D);
extern void nr_kohana_enable(TSRMLS_D);
extern void nr_laminas3_enable(TSRMLS_D);
extern void nr_laravel_enable(TSRMLS_D);
extern void nr_lumen_enable(TSRMLS_D);
extern void nr_magento1_enable(TSRMLS_D);
extern void nr_magento2_enable(TSRMLS_D);
extern void nr_mediawiki_enable(TSRMLS_D);
Expand Down
209 changes: 209 additions & 0 deletions agent/fw_lumen.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
/*
* Copyright 2020 New Relic Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/

#include "php_agent.h"
#include "php_call.h"
#include "php_error.h"
#include "php_user_instrument.h"
#include "php_execute.h"
#include "php_wrapper.h"
#include "php_hash.h"
#include "fw_hooks.h"
#include "util_logging.h"
#include "util_memory.h"
#include "util_strings.h"

/*
* Sets the web transaction name. If strip_base == true,
* leading class path components will be stripped.
*/
static int nr_lumen_name_the_wt(const char* name TSRMLS_DC,
const char* lumen_version,
bool strip_base) {
const char* path = NULL;

if (NULL == name) {
return NR_FAILURE;
}

if (strip_base) {
path = strrchr(name, '\\');
// Backslash was not found
if (NULL == path) {
path = name;
} else {
path += 1;
}
}

nr_txn_set_path(
lumen_version, NRPRG(txn), path, NR_PATH_TYPE_ACTION,
NR_OK_TO_OVERWRITE); /* Watch out: this name is OK to overwrite */

return NR_SUCCESS;
}

/*
* Wrapper around nr_lumen_name_the_wt for zval strings
*/
static int nr_lumen_name_the_wt_from_zval(const zval* name TSRMLS_DC,
const char* lumen_version,
bool strip_base) {
int rc = NR_FAILURE;
if (nrlikely(nr_php_is_zval_non_empty_string(name))) {
char* name_str = nr_strndup(Z_STRVAL_P(name), Z_STRLEN_P(name));
rc = nr_lumen_name_the_wt(name_str TSRMLS_CC, lumen_version, strip_base);
nr_free(name_str);
}

return rc;
}

/*
* Core transaction naming logic. Wraps the function that correlates
* requests to routes
*/
NR_PHP_WRAPPER(nr_lumen_handle_found_route) {
zval* route_info = NULL;

/* Warning avoidance */
(void)wraprec;

/* Verify that we are using Lumen, otherwise bail. */
NR_PHP_WRAPPER_REQUIRE_FRAMEWORK(NR_FW_LUMEN);

/* $routeInfo object used by Application */
route_info = nr_php_arg_get(1, NR_EXECUTE_ORIG_ARGS TSRMLS_CC);

/* We expect route_info to be an array. At index 1, if we see an
* 'as' key, then we have access to the route, otherwise, if we have
* a 'uses' key we have access to the controller and action.
* See: https://lumen.laravel.com/docs/8.x/routing#named-routes
*/
if (!nr_php_is_zval_valid_array(route_info)) {
nrl_verbosedebug(NRL_TXN, "Lumen: $routeInfo was not an array");
NR_PHP_WRAPPER_CALL;
goto end;
}

NR_PHP_WRAPPER_CALL;

/* obtain $routeInfo[1] */
zend_ulong idx = 1;
zval* route_info_pos
= nr_php_zend_hash_index_find(Z_ARRVAL_P(route_info), idx);

/* obtain $routeInfo[1]['as'] for route name */
zval* route_name = NULL;
if (NULL != route_info_pos) {
route_name = nr_php_zend_hash_find(Z_ARRVAL_P(route_info_pos), "as");
}

if (NULL != route_name) {
if (NR_SUCCESS
!= nr_lumen_name_the_wt_from_zval(route_name TSRMLS_CC, "Lumen", 0)) {
nrl_verbosedebug(NRL_TXN, "Lumen: located route name is a non-string");
}
} else {
/* No route located, use controller instead */
nrl_verbosedebug(
NRL_TXN,
"Lumen: unable locate route, attempting to use controller instead");

/* obtain $routeInfo[1]['uses'] for controller name */
zval* controller_name
= nr_php_zend_hash_find(Z_ARRVAL_P(route_info_pos), "uses");

if (NULL != controller_name) {
if (NR_SUCCESS
!= nr_lumen_name_the_wt_from_zval(controller_name TSRMLS_CC, "Lumen",
1)) {
nrl_verbosedebug(NRL_TXN,
"Lumen: located controller name is a non-string");
}

} else {
nrl_verbosedebug(NRL_TXN, "Lumen: unable to locate controller or route");
}
}

end:
nr_php_arg_release(&route_info);
}
NR_PHP_WRAPPER_END

/*
* Exception handling logic. Wraps the function that routes
* exceptions to their respective handlers
*/
NR_PHP_WRAPPER(nr_lumen_exception) {
zval* exception = NULL;

NR_UNUSED_SPECIALFN;
(void)wraprec;

NR_PHP_WRAPPER_REQUIRE_FRAMEWORK(NR_FW_LUMEN);

#if ZEND_MODULE_API_NO >= ZEND_5_4_X_API_NO
const char* class_name = NULL;
const char* ignored = NULL;
#else
char* class_name = NULL;
char* ignored = NULL;
#endif /* PHP >= 5.4 */

char* name = NULL;

/*
* When the exception handler renders the response, name the transaction
* after the exception handler using the same format used for controller
* actions. e.g. Controller@action.
*/
class_name = get_active_class_name(&ignored TSRMLS_CC);
name = nr_formatf("%s@%s", class_name, get_active_function_name(TSRMLS_C));
nr_lumen_name_the_wt(name TSRMLS_CC, "Lumen", 1);
nr_free(name);

exception = nr_php_arg_get(1, NR_EXECUTE_ORIG_ARGS TSRMLS_CC);
if (NULL == exception) {
nrl_verbosedebug(NRL_FRAMEWORK, "%s: $e is NULL", __func__);
NR_PHP_WRAPPER_CALL;
goto end;
}

NR_PHP_WRAPPER_CALL;

nr_status_t st;
int priority = nr_php_error_get_priority(E_ERROR);

st = nr_php_error_record_exception(NRPRG(txn), exception, priority,
NULL /* use default prefix */,
&NRPRG(exception_filters) TSRMLS_CC);

if (NR_FAILURE == st) {
nrl_verbosedebug(NRL_FRAMEWORK, "%s: unable to record exception", __func__);
}

end:
nr_php_arg_release(&exception);
}
NR_PHP_WRAPPER_END

void nr_lumen_enable(TSRMLS_D) {
/*
* We set the path to 'unknown' to prevent having to name routing errors.
* This follows what is done in the symfony logic
*/
nr_txn_set_path("Lumen", NRPRG(txn), "unknown", NR_PATH_TYPE_ACTION,
NR_OK_TO_OVERWRITE);

nr_php_wrap_user_function(
NR_PSTR("Laravel\\Lumen\\Application::handleFoundRoute"),
nr_lumen_handle_found_route TSRMLS_CC);

nr_php_wrap_user_function(
NR_PSTR("Laravel\\Lumen\\Application::sendExceptionToHandler"),
nr_lumen_exception TSRMLS_CC);
}
3 changes: 2 additions & 1 deletion agent/php_execute.c
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,8 @@ static const nr_framework_table_t all_frameworks[] = {
{"Laravel", "laravel", "bootstrap/cache/compiled.php", 0, nr_laravel_enable,
NR_FW_LARAVEL}, /* 5.1.0-x */

{"Lumen", "lumen", "lumen-framework/src/helpers.php", 0, nr_lumen_enable, NR_FW_LUMEN},

{"Magento", "magento", "app/mage.php", 0, nr_magento1_enable,
NR_FW_MAGENTO1},
{"Magento2", "magento2", "magento/framework/app/bootstrap.php", 0,
Expand Down Expand Up @@ -518,7 +520,6 @@ static nr_library_table_t libraries[] = {
{"CakePHP3", "cakephp/src/core/functions.php", NULL},
{"Fuel", "fuel/core/classes/fuel.php", NULL},
{"Lithium", "lithium/core/libraries.php", NULL},
{"Lumen", "lumen-framework/src/helpers.php", NULL},
{"Phpbb", "phpbb/request/request.php", NULL},
{"Phpixie2", "phpixie/core/classes/phpixie/pixie.php", NULL},
{"Phpixie3", "phpixie/framework.php", NULL},
Expand Down
1 change: 1 addition & 0 deletions agent/php_newrelic.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ typedef enum {
NR_FW_JOOMLA,
NR_FW_KOHANA,
NR_FW_LARAVEL,
NR_FW_LUMEN,
NR_FW_MAGENTO1,
NR_FW_MAGENTO2,
NR_FW_MEDIAWIKI,
Expand Down

0 comments on commit bab8316

Please sign in to comment.