Skip to content

feat(agent): add function to convert ini to env #892

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion agent/Makefile.frag
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,10 @@ TEST_BINARIES = \
tests/test_pdo_mysql \
tests/test_pdo_pgsql \
tests/test_pgsql \
tests/test_php_error \
tests/test_php_error \
tests/test_php_execute \
tests/test_php_minit \
tests/test_php_nrini \
tests/test_php_stack \
tests/test_php_stacked_segment \
tests/test_php_wrapper \
Expand Down
125 changes: 93 additions & 32 deletions agent/php_nrini.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "php_hash.h"
#include "php_internal_instrument.h"
#include "php_user_instrument.h"
#include "php_nrini.h"

#include "nr_commands.h"
#include "nr_configstrings.h"
Expand Down Expand Up @@ -222,6 +223,62 @@

ZEND_DECLARE_MODULE_GLOBALS(newrelic)

char* nr_ini_to_env(const char* ini_name) {
const int NR_INI_PREFIX_LEN = nr_strlen("newrelic.");
char* env_name = NULL;
char* buf = NULL;
char* ini_upper = NULL;
int ini_len = nr_strlen(ini_name);

// 'newrelic.' is 9 characters - anything less should be rejected.
if (NULL == ini_name || nr_strlen(ini_name) <= NR_INI_PREFIX_LEN) {
return NULL;
}

// ini value should start with the 'newrelic.' prefix
if (0 != nr_stridx(ini_name, "newrelic.")) {
return NULL;
}

// algorithm:
// 1. uppercase ini string
// 2. iterate through uppercase ini string and copy each character to the new
// buffer, swapping each '.' with '_'.
// 3. snprintf append the string to 'NEW_RELIC'
// 4. return result

ini_upper = nr_string_to_uppercase(ini_name);

buf = (char*)nr_zalloc(ini_len - NR_INI_PREFIX_LEN + 1);

for (int i = NR_INI_PREFIX_LEN, j = 0; i < nr_strlen(ini_upper); i++) {
if (NR_INI_PREFIX_LEN == i
&& ('.' == ini_upper[i] || '_' == ini_upper[i])) {
// skip if the first character is '.' or '_' to avoid double underscores
continue;
} else if ('_' == ini_upper[i] && '_' == ini_upper[i - 1]) {
// skip double '_' characters
continue;
} else if ('.' == ini_upper[i] && '_' != ini_upper[i - 1]) {
// replace a '.' with '_', provided the previous character is not also '_'
buf[j] = '_';
} else {
// copy the character
buf[j] = ini_upper[i];
}
j++;
}

env_name = (char*)nr_zalloc(ini_len + 2);

snprintf(env_name, ini_len + 2, "%s_%s", "NEW_RELIC", buf);

nr_free(buf);
nr_free(ini_upper);

return env_name;
}

typedef void (*foreach_fn_t)(const char* name, int namelen TSRMLS_DC);

static void foreach_list(const char* str, foreach_fn_t f_eachname TSRMLS_DC) {
Expand Down Expand Up @@ -3039,42 +3096,46 @@ STD_PHP_INI_ENTRY_EX("newrelic.application_logging.metrics.enabled",
zend_newrelic_globals,
newrelic_globals,
nr_enabled_disabled_dh)
STD_PHP_INI_ENTRY_EX("newrelic.application_logging.forwarding.context_data.enabled",
"0",
NR_PHP_REQUEST,
nr_boolean_mh,
log_context_data_attributes.enabled,
zend_newrelic_globals,
newrelic_globals,
nr_enabled_disabled_dh)
STD_PHP_INI_ENTRY_EX("newrelic.application_logging.forwarding.context_data.include",
"",
NR_PHP_REQUEST,
nr_string_mh,
log_context_data_attributes.include,
zend_newrelic_globals,
newrelic_globals,
0)
STD_PHP_INI_ENTRY_EX("newrelic.application_logging.forwarding.context_data.exclude",
"",
NR_PHP_REQUEST,
nr_string_mh,
log_context_data_attributes.exclude,
zend_newrelic_globals,
newrelic_globals,
0)
STD_PHP_INI_ENTRY_EX(
"newrelic.application_logging.forwarding.context_data.enabled",
"0",
NR_PHP_REQUEST,
nr_boolean_mh,
log_context_data_attributes.enabled,
zend_newrelic_globals,
newrelic_globals,
nr_enabled_disabled_dh)
STD_PHP_INI_ENTRY_EX(
"newrelic.application_logging.forwarding.context_data.include",
"",
NR_PHP_REQUEST,
nr_string_mh,
log_context_data_attributes.include,
zend_newrelic_globals,
newrelic_globals,
0)
STD_PHP_INI_ENTRY_EX(
"newrelic.application_logging.forwarding.context_data.exclude",
"",
NR_PHP_REQUEST,
nr_string_mh,
log_context_data_attributes.exclude,
zend_newrelic_globals,
newrelic_globals,
0)

/*
* Vulnerability Management
*/
STD_PHP_INI_ENTRY_EX("newrelic.vulnerability_management.package_detection.enabled",
"1",
NR_PHP_REQUEST,
nr_boolean_mh,
vulnerability_management_package_detection_enabled,
zend_newrelic_globals,
newrelic_globals,
nr_enabled_disabled_dh)
STD_PHP_INI_ENTRY_EX(
"newrelic.vulnerability_management.package_detection.enabled",
"1",
NR_PHP_REQUEST,
nr_boolean_mh,
vulnerability_management_package_detection_enabled,
zend_newrelic_globals,
newrelic_globals,
nr_enabled_disabled_dh)

PHP_INI_END() /* } */

Expand Down
10 changes: 10 additions & 0 deletions agent/php_nrini.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
* Copyright 2020 New Relic Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*
* This file declares nrini functions.
*/
#ifndef PHP_NRINI_HDR
#define PHP_NRINI_HDR
extern char* nr_ini_to_env(const char* ini_name);
#endif /* PHP_NRINI_HDR */
75 changes: 75 additions & 0 deletions agent/tests/test_php_nrini.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright 2020 New Relic Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/

#include "tlib_main.h"
#include "tlib_php.h"

#include "php_agent.h"
#include "php_nrini.h"

static void test_nr_ini_to_env(void) {
char* res = NULL;

res = nr_ini_to_env("newrelic.enabled");

tlib_pass_if_str_equal("ini converted to env", "NEW_RELIC_ENABLED", res);

nr_free(res);

res = nr_ini_to_env(
"newrelic.application_logging.forwarding.context_data.include");

tlib_pass_if_str_equal(
"ini converted to env",
"NEW_RELIC_APPLICATION_LOGGING_FORWARDING_CONTEXT_DATA_INCLUDE", res);

nr_free(res);

res = nr_ini_to_env("newrelic.12345");

tlib_pass_if_str_equal("numerical values handled correctly",
"NEW_RELIC_12345", res);

nr_free(res);

res = nr_ini_to_env("not_a_newrelic.ini_value");

tlib_pass_if_null("invalid ini not converted", res);

nr_free(res);

res = nr_ini_to_env("newrelic.");

tlib_pass_if_null("no value after prefix", res);

nr_free(res);

res = nr_ini_to_env(NULL);

tlib_pass_if_null("reject null values", res);

nr_free(res);

res = nr_ini_to_env("newrelic.ini__value");

tlib_pass_if_str_equal("double underscores handled correctly",
"NEW_RELIC_INI_VALUE", res);

nr_free(res);

res = nr_ini_to_env("newrelic._option_");

tlib_pass_if_str_equal("dot and underscores handled correctly",
"NEW_RELIC_OPTION_", res);

nr_free(res);
}

tlib_parallel_info_t parallel_info
= {.suggested_nthreads = -1, .state_size = 0};

void test_main(void* p NRUNUSED) {
test_nr_ini_to_env();
}
19 changes: 19 additions & 0 deletions axiom/util_strings.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,25 @@ char* nr_string_to_lowercase(const char* str) {
return low;
}

char* nr_string_to_uppercase(const char* str) {
int i;
char* upper;

if (NULL == str) {
return NULL;
}

upper = nr_strdup(str);
if (NULL == upper) {
return NULL;
}

for (i = 0; upper[i]; i++) {
upper[i] = nr_toupper(upper[i]);
}
return upper;
}

char* nr_formatf(const char* fmt, ...) {
int rv;
va_list ap;
Expand Down
11 changes: 11 additions & 0 deletions axiom/util_strings.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@
*/
extern char* nr_string_to_lowercase(const char* str);

/*
* Purpose : Convert a string to upper case, following USASCII rules, returning
* a newly allocated string.
*
* Params : 1. The string to uppercase.
*
* Returns : The newly created string. The caller must arrange to free the
* string.
*/
extern char* nr_string_to_uppercase(const char* str);

/*
* Purpose : Wrap asprintf to increase convenience and safety: asprintf behavior
* is not in POSIX, and the return string may not be defined in the
Expand Down