diff --git a/.github/workflows/auto-instrumentation.yml b/.github/workflows/auto-instrumentation.yml index 80408b1d1a..569b11f51b 100644 --- a/.github/workflows/auto-instrumentation.yml +++ b/.github/workflows/auto-instrumentation.yml @@ -34,6 +34,9 @@ jobs: - name: Build libsplunk.so run: make -C instrumentation dist ARCH=${{ matrix.ARCH }} + - name: Run tests + run: make -C instrumentation tests ARCH=${{ matrix.ARCH }} + - name: Upload artifact uses: actions/upload-artifact@v3 with: diff --git a/.gitignore b/.gitignore index 79d95aa012..bce3b63d29 100644 --- a/.gitignore +++ b/.gitignore @@ -45,4 +45,5 @@ deployments/heroku/test/node_modules /instrumentation/dist/ /instrumentation/obj/ /instrumentation/so/ -/instrumentation/tests +/instrumentation/tests/java/libsplunk.so +/instrumentation/tests/nodejs/libsplunk.so \ No newline at end of file diff --git a/instrumentation/Dockerfile b/instrumentation/Dockerfile index 42f17fa504..d219dbab51 100644 --- a/instrumentation/Dockerfile +++ b/instrumentation/Dockerfile @@ -7,7 +7,4 @@ RUN apt-get update && \ WORKDIR /libsplunk COPY src /libsplunk/src -COPY testdata/instrumentation-default.conf /libsplunk/testdata/instrumentation-default.conf -COPY testdata/instrumentation-options.conf /libsplunk/testdata/instrumentation-options.conf -COPY install/instrumentation.conf /libsplunk/install/instrumentation.conf COPY Makefile /libsplunk/Makefile diff --git a/instrumentation/Makefile b/instrumentation/Makefile index 967d8721cc..bd03269471 100644 --- a/instrumentation/Makefile +++ b/instrumentation/Makefile @@ -18,34 +18,11 @@ obj: clean: rm -f tests so/* obj/* -obj/logger.o: obj src/logger.c src/logger.h - gcc -c -Wall -Werror -fpic -o obj/logger.o src/logger.c +obj/main.o: obj src/main.c + gcc -c -Wall -Werror -fpic -o obj/main.o src/main.c -obj/config.o: obj src/config.c src/config.h - gcc -c -Wall -Werror -fpic -o obj/config.o src/config.c - -obj/metrics_client.o: obj src/metrics_client.c src/metrics_client.h - gcc -c -Wall -Werror -fpic -o obj/metrics_client.o src/metrics_client.c - -obj/splunk.o: obj src/splunk.c src/splunk.h - gcc -c -Wall -Werror -fpic -o obj/splunk.o src/splunk.c - -obj/args.o: obj src/args.c src/args.h - gcc -c -Wall -Werror -fpic -o obj/args.o src/args.c - -obj/cmdline_reader.o: obj src/cmdline_reader.c src/cmdline_reader.h - gcc -c -Wall -Werror -fpic -o obj/cmdline_reader.o src/cmdline_reader.c - -so/libsplunk.so: obj so obj/logger.o obj/config.o obj/metrics_client.o obj/cmdline_reader.o obj/args.o obj/splunk.o - gcc -shared -o so/libsplunk.so obj/logger.o obj/config.o obj/metrics_client.o obj/cmdline_reader.o obj/args.o obj/splunk.o - -tests: src/test_main.h src/test_main.c src/test_utils.h src/test_utils.c src/logger.h src/test_logger.c \ -src/metrics_client.h src/cmdline_reader.h src/cmdline_reader_test.c obj/config.o obj/metrics_client.o obj/args.o obj/splunk.o - gcc -g -o tests src/test_main.c src/test_utils.c src/test_logger.c src/cmdline_reader_test.c obj/config.o obj/metrics_client.o obj/args.o obj/splunk.o - -.PHONY: test -test: tests - ./tests +so/libsplunk.so: obj so obj/main.o + gcc -shared -o so/libsplunk.so obj/main.o .PHONY: dist dist: @@ -53,7 +30,7 @@ dist: docker buildx build --platform linux/$(ARCH) --build-arg DOCKER_REPO=$(DOCKER_REPO) -o type=image,name=libsplunk-builder:$(ARCH),push=false . docker rm -f libsplunk-builder 2>/dev/null || true docker run -d --platform linux/$(ARCH) --name libsplunk-builder libsplunk-builder:$(ARCH) sleep inf - docker exec libsplunk-builder make test all + docker exec libsplunk-builder make all docker cp libsplunk-builder:/libsplunk/so/libsplunk.so dist/libsplunk_$(ARCH).so docker rm -f libsplunk-builder @@ -70,7 +47,6 @@ endif .PHONY: install install: all uninstall mkdir -p $(INSTALL_DIR) - cp install/instrumentation.conf $(INSTALL_DIR) cp splunk-otel-javaagent.jar $(INSTALL_DIR) cp so/libsplunk.so $(INSTALL_DIR) echo $(INSTALL_DIR)/libsplunk.so > /etc/ld.so.preload @@ -92,3 +68,14 @@ docker-build: .PHONY: docker-run docker-run: docker run --rm -it -v `pwd`:/instr instr-devel + +.PHONY: tests +tests: test-java test-nodejs + +.PHONY: test-java +test-java: dist + (cd tests/java && ./test.sh) + +.PHONY: test-nodejs +test-nodejs: dist + (cd tests/nodejs && ./test.sh) \ No newline at end of file diff --git a/instrumentation/README.md b/instrumentation/README.md deleted file mode 100644 index fc6604f7c2..0000000000 --- a/instrumentation/README.md +++ /dev/null @@ -1,181 +0,0 @@ -# Linux Java Auto Instrumentation - -This directory contains functionality to automatically instrument your local Java applications so that they capture and -report distributed traces to Splunk APM. - -## Operation - -This directory contains functionality for building a Linux .so (shared object) file, which, in conjunction with a -reference to that file in -`/etc/ld.so.preload` (provided by an installer defined elsewhere) causes processes on the host to run this .so before -the main executable runs. If the executable that's starting is not named `java`, the .so quits silently and the -executable starts normally. Otherwise, it attempts to set environment variables that will cause the -[Splunk OTel Java JAR](https://github.com/signalfx/splunk-otel-java) (also provided by the installer) to instrument the -soon-to-be running Java application. In this way, all Java applications on the host will be automatically instrumented -by the Splunk OTel Java agent. - -Once instrumented, Java executables send traces to a locally running -[Splunk Open Telemetry Collector](https://github.com/signalfx/splunk-otel-collector) -(installed separately) and then on to Splunk APM. - -## Configuration File - -At startup, the shared object reads the config file, `/usr/lib/splunk-instrumentation/instrumentation.conf` which by -default, looks like this: - -``` -java_agent_jar=/usr/lib/splunk-instrumentation/splunk-otel-javaagent.jar -``` - -The `java_agent_jar` parameter is set to the default location of the agent jar. - -### Supported parameters - -#### `java_agent_jar` (required) - -The full path to the auto instrumentation JAR (provided by the installer). - -#### `service_name` (optional) - -This is an optional override for the service name that would otherwise be generated by the shared object before Java -startup. By default, this line is commented out, but can be uncommented to override the generated name. If this -parameter is set, all instrumented Java applications on this host will have the specified service name (via the -OTEL_SERVICE_NAME environment variable). If this override is set and `generate_service_name` is also explicitly set to -`false`, that parameter will win, and the service name will not be set. - -#### `resource_attributes` (optional -- typically set by the installer script) - -This value, if present, should contain a list of name-value pairs (separated by `=`s and pairs separated by `,`s) to -which the .so will set the OTEL_RESOURCE_ATTRIBUTES environment variable. The OTEL_RESOURCE_ATTRIBUTES environment -variable will then be picked up by the Java instrumentation jar. Typically, it will be set to something like: - -`resource_attributes=deployment.environment=test` - -to set the deployment environment for the Splunk backend. - -#### `disable_telemetry` (optional) - -Set this value to `true` to disable the preloader from sending the `splunk.linux-autoinstr.executions` metric to the -local collector. Default: `false`. - -#### `generate_service_name` (optional) - -Set this value to `false` to prevent the preloader from setting the `OTEL_SERVICE_NAME` environment variable. If this -value is `false`, the preloader will not set `OTEL_SERVICE_NAME`, and the soon-to-be running Java instrumentation -library will attempt to set it instead (in the future, this will be the default behavior). Default: `true`. - -#### `enable_profiler` (optional) - -Set this value to `true` to pass `-Dsplunk.profiler.enabled=true` to the starting Java executable, which will enable -[AlwaysOn CPU Profiling](https://docs.splunk.com/Observability/apm/profiling/get-data-in-profiling.html). -Default: `false`. - -#### `enable_profiler_memory` (optional) - -Set this value to `true` to pass `-Dsplunk.profiler.memory.enabled=true` to the starting Java executable, which will -enable -[AlwaysOn Memory Profiling](https://docs.splunk.com/Observability/apm/profiling/get-data-in-profiling.html). -Default: `false`. - -#### `enable_metrics` (optional) - -Set this value to `true` to pass `-Dsplunk.metrics.enabled=true` to the starting Java executable, which will enable -[exporting metrics](https://github.com/signalfx/splunk-otel-java/blob/main/docs/metrics.md). Default: `false`. - -### Syntax - -To add a comment or comment out a line, start it with a `#`. - -Not supported (and unnecessary) are: - -* Quoting of any kind -* Whitespace on either side of the equals sign -* Leading whitespace - -### Environment Variables - -The way the .so causes a Java executable to be instrumented is by setting the environment variables, JAVA_TOOL_OPTIONS -and OTEL_SERVICE_NAME, and optionally, OTEL_RESOURCE_ATTRIBUTES. - -#### JAVA_TOOL_OPTIONS - -This environment variable contains a `-javaagent` flag set to the full path of the Splunk OTel Java JAR. - -e.g. `JAVA_TOOL_OPTIONS='-javaagent:/usr/lib/splunk-instrumentation/splunk-otel-javaagent.jar'` - -This variable is populated by the .so by concatenating the `java_agent_jar` attribute in the config to a `-javaagent:` -prefix, and then appending any additional system properties specified in the configuration file. - -#### OTEL_SERVICE_NAME - -This environment variable sets the service name for the soon-to-be running Java application, usually derived from the -arguments of the Java executable (can be overridden via the config). - -This variable is set directly from the `service_name` attribute in the config. - -_Meta: link to docs about how service name is used and why it's required._ - -#### OTEL_RESOURCE_ATTRIBUTES - -This environment variable contains a list of name-value pairs (separated by `=`s) passed on to the Java instrumentation -jar. - -This variable is set directly from the optional `resource_attributes` attribute in the config. - -##### Service Name Generation - -The OTEL_SERVICE_NAME environment variable is set to a value that the .so generates from the arguments passed to the -Java executable. The .so does this by reading the arguments to the Java application from left to right, ignoring -arguments that look like flags (that start with a `-`), and reading arguments containing `.jar`, splitting those on `:`, -then on `/`, removing known path parts such as `usr`, `local`, etc., truncating the `.jar` extension, replacing dots -with dashes, removing segments, and concatenating the result with dashes. If while scanning the arguments, it finds a -main class name, it just returns the main class name with dots replaced with dashes and caps to lowercase, otherwise, -it returns the munged jar names. - -For example, the following command: - -``` -/usr/bin/java -jar app/petclinic/spring-petclinic-2.4.5.jar -``` - -produces a service name of: - -``` -app-petclinic-spring-2.4.5 -``` - -The following, more complex command: - -``` -java -Djava.util.logging.config.file=\ -/usr/local/apache-tomcat/8.5.4/conf/logging.properties \ --Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager \ --Djdk.tls.ephemeralDHKeySize=2048 \ --classpath \ -/usr/local/apache-tomcat/8.5.4/bin/bootstrap.jar:\ -/usr/local/apache-tomcat/8.5.4/bin/tomcat-juli.jar \ --Dcatalina.base=/usr/local/apache-tomcat/8.5.4 \ --Dcatalina.home=/usr/local/apache-tomcat/8.5.4 \ --Djava.io.tmpdir=/usr/local/apache-tomcat/8.5.4/temp \ -org.apache.catalina.startup.Bootstrap start -``` - -produces a service name of: - -``` -org-apache-catalina-startup-bootstrap -``` - -## Disabling - -Short of uninstalling the package, there are a few safe ways of disabling auto instrumentation - -* Set `DISABLE_SPLUNK_AUTOINSTRUMENTATION` to any non-empty value other than false, FALSE, or 0 -* Set `JAVA_TOOL_OPTIONS` to some value that you want the JVM to pick up -* Delete or move the config `instrumentation.conf` file - -## Files - -* /usr/lib/splunk-instrumentation/libsplunk.so -* /usr/lib/splunk-instrumentation/instrumentation.conf -* /usr/lib/splunk-instrumentation/splunk-otel-javaagent.jar diff --git a/instrumentation/install/instrumentation.conf b/instrumentation/install/instrumentation.conf deleted file mode 100644 index 9c4631f816..0000000000 --- a/instrumentation/install/instrumentation.conf +++ /dev/null @@ -1,10 +0,0 @@ -java_agent_jar=/usr/lib/splunk-instrumentation/splunk-otel-javaagent.jar -#resource_attributes=deployment.environment=my.environment -#service_name=hardcoded.service - -# note: any of the the following lines may be uncommented to override defaults -#disable_telemetry=true -#generate_service_name=false -#enable_profiler=true -#enable_profiler_memory=true -#enable_metrics=true diff --git a/instrumentation/packaging/fpm/common.sh b/instrumentation/packaging/fpm/common.sh index 4080931ec2..5236e5f936 100644 --- a/instrumentation/packaging/fpm/common.sh +++ b/instrumentation/packaging/fpm/common.sh @@ -26,14 +26,12 @@ PKG_URL="https://github.com/signalfx/splunk-otel-collector" LIBSPLUNK_INSTALL_PATH="/usr/lib/splunk-instrumentation/libsplunk.so" JAVA_AGENT_INSTALL_PATH="/usr/lib/splunk-instrumentation/splunk-otel-javaagent.jar" -CONFIG_INSTALL_PATH="/usr/lib/splunk-instrumentation/instrumentation.conf" JAVA_AGENT_RELEASE_PATH="${FPM_DIR}/../java-agent-release.txt" JAVA_AGENT_RELEASE_URL="https://github.com/signalfx/splunk-otel-java/releases/" POSTINSTALL_PATH="$FPM_DIR/postinstall.sh" PREUNINSTALL_PATH="$FPM_DIR/preuninstall.sh" -CONFIG_PATH="$REPO_DIR/instrumentation/install/instrumentation.conf" get_version() { commit_tag="$( git -C "$REPO_DIR" describe --abbrev=0 --tags --exact-match --match 'v[0-9]*' 2>/dev/null || true )" @@ -78,9 +76,4 @@ setup_files_and_permissions() { cp -f "$java_agent" "$buildroot/$JAVA_AGENT_INSTALL_PATH" sudo chown root:root "$buildroot/$JAVA_AGENT_INSTALL_PATH" sudo chmod 755 "$buildroot/$JAVA_AGENT_INSTALL_PATH" - - mkdir -p "$buildroot/$(dirname $CONFIG_INSTALL_PATH)" - cp -f "$CONFIG_PATH" "$buildroot/$CONFIG_INSTALL_PATH" - sudo chown root:root "$buildroot/$CONFIG_INSTALL_PATH" - sudo chmod 644 "$buildroot/$CONFIG_INSTALL_PATH" } diff --git a/instrumentation/packaging/fpm/deb/build.sh b/instrumentation/packaging/fpm/deb/build.sh index 457c2ac9aa..d804b39853 100755 --- a/instrumentation/packaging/fpm/deb/build.sh +++ b/instrumentation/packaging/fpm/deb/build.sh @@ -53,7 +53,6 @@ sudo fpm -s dir -t deb -n "$PKG_NAME" -v "$VERSION" -f -p "$OUTPUT_DIR" \ --deb-no-default-config-files \ --depends sed \ --depends grep \ - --config-files "$CONFIG_INSTALL_PATH" \ "$buildroot/"=/ dpkg -c "${OUTPUT_DIR}/${PKG_NAME}_${VERSION}_${ARCH}.deb" diff --git a/instrumentation/packaging/fpm/rpm/build.sh b/instrumentation/packaging/fpm/rpm/build.sh index 6bfc96e621..ae9dd3822e 100755 --- a/instrumentation/packaging/fpm/rpm/build.sh +++ b/instrumentation/packaging/fpm/rpm/build.sh @@ -62,7 +62,6 @@ sudo fpm -s dir -t rpm -n "$PKG_NAME" -v "$VERSION" -f -p "$OUTPUT_DIR" \ --before-remove "$PREUNINSTALL_PATH" \ --depends sed \ --depends grep \ - --config-files "$CONFIG_INSTALL_PATH" \ "$buildroot/"=/ rpm -qpli "${OUTPUT_DIR}/${PKG_NAME}-${VERSION}-1.${ARCH}.rpm" diff --git a/instrumentation/packaging/fpm/test.sh b/instrumentation/packaging/fpm/test.sh index 2299716dee..f690c4f121 100755 --- a/instrumentation/packaging/fpm/test.sh +++ b/instrumentation/packaging/fpm/test.sh @@ -36,10 +36,6 @@ if ! grep -q "$LIBSPLUNK_INSTALL_PATH" /etc/ld.so.preload; then echo "$LIBSPLUNK_INSTALL_PATH not found in /etc/ld.so.preload" >&2 exit 1 fi -if [ ! -f "$CONFIG_INSTALL_PATH" ]; then - echo "$CONFIG_INSTALL_PATH not found!" >&2 - exit 1 -fi ldd "$LIBSPLUNK_INSTALL_PATH" @@ -54,10 +50,6 @@ if ! grep -q "$LIBSPLUNK_INSTALL_PATH" /etc/ld.so.preload; then echo "$LIBSPLUNK_INSTALL_PATH not found in /etc/ld.so.preload" >&2 exit 1 fi -if [ ! -f "$CONFIG_INSTALL_PATH" ]; then - echo "$CONFIG_INSTALL_PATH not found!" >&2 - exit 1 -fi ldd "$LIBSPLUNK_INSTALL_PATH" diff --git a/instrumentation/src/args.c b/instrumentation/src/args.c deleted file mode 100644 index d18e97b8a1..0000000000 --- a/instrumentation/src/args.c +++ /dev/null @@ -1,265 +0,0 @@ -#include "args.h" -#include "cmdline_reader.h" -#include -#include -#include -#include - -#define MAX_ARG_LEN 8192 - -// individual args are copied onto the heap and should be freed -int get_cmdline_args(char **args, cmdline_reader cr, int max_args, int max_cmdline_len, logger log) { - int cmdline_idx = 0; - int args_idx = 0; - int arg_char_offset = 0; - char arg[MAX_ARG_LEN]; - cmdline_reader_open(cr); - while (!cmdline_reader_is_eof(cr)) { - if (cmdline_idx++ == max_cmdline_len) { - log_warning(log, "command line too long, truncating"); - break; - } - char c = cmdline_reader_get_char(cr); - arg[arg_char_offset] = c; - arg_char_offset += 1; - if (c == 0 || arg_char_offset == MAX_ARG_LEN) { - args[args_idx] = strndup(arg, MAX_ARG_LEN); - args_idx += 1; - if (args_idx == max_args) { - break; - } - arg_char_offset = 0; - } - } - return args_idx; -} - -void free_cmdline_args(char **args, int num_args) { - for (int i = 0; i < num_args; ++i) { - free(args[i]); - } -} - -void format_arg(char *str) { - for (; *str != 0; ++str) { - if (*str == '.' || *str == '/') { - *str = '-'; - } else { - *str = (char) tolower(*str); - } - } -} - -void init_tokenset(struct tokenset *tks) { - tks->i = 0; -} - -void free_tokenset(struct tokenset *tks) { - for (int i = 0; i < tks->i; ++i) { - free(tks->tokens[i]); - } -} - -void add_token(struct tokenset *tks, char *token) { - // it is unlikely, but if we have too many tokens, just stop adding them - if (tks->i < TOKENSET_MAX_SIZE) { - tks->tokens[tks->i++] = strdup(token); - } -} - -int has_token(struct tokenset *tks, char *token) { - // not doing a set implementation at this time since size of array is small - for (int i = 0; i < tks->i; ++i) { - if (strcmp(tks->tokens[i], token) == 0) { - return 1; - } - } - return 0; -} - -void generate_servicename_from_args(char *dest, char **args, int num_args) { - struct tokenset tks; - init_tokenset(&tks); - for (int i = 0; i < num_args; ++i) { - char *arg = args[i]; - if (strstr(arg, ".jar") != NULL) { - transform_multi_jars(dest, arg, &tks); - } - if (arg[0] == '-') { - continue; - } - if (is_legal_java_main_class_with_module(arg)) { - format_arg(arg); - strcpy(dest, arg); - return; - } - } - free_tokenset(&tks); -} - -// concatenates colon separated jars and removes non-uniquely-identifying dirs as well as double dots from the path -// `arg` is e.g. "/usr/local/apache-tomcat/8.5.4/bin/bootstrap.jar:/usr/local/apache-tomcat/8.5.4/bin/tomcat-juli.jar" -// `dest` is on the stack, `arg` is on the heap -void transform_multi_jars(char *dest, char *arg, struct tokenset *tks) { - char *token; - while ((token = strsep(&arg, ":")) != NULL) { - char transformed_jar_path_elements[MAX_ARG_LEN] = ""; - transform_jar_path_elements(transformed_jar_path_elements, token); - - char deduped[MAX_ARG_LEN] = ""; - dedupe_hyphenated(deduped, transformed_jar_path_elements, tks); - - if (strlen(dest) > 0) { - strcat(dest, "-"); - } - strcat(dest, deduped); - } -} - -void tolowerstr(char *str); - -void transform_jar_path_elements(char *out, char *path) { - // path = e.g. "/usr/local/apache-tomcat/8.5.4/bin/bootstrap.jar" - char *token; - while ((token = strsep(&path, "/")) != NULL) { - if (!is_unique_path_element(token)) { - continue; - } - if (strlen(out) > 0) { - strcat(out, "-"); - } - truncate_extension(token); - tolowerstr(token); - strcat(out, token); - } -} - -void tolowerstr(char *str) { - for (int i = 0; i < strlen(str); ++i) { - str[i] = (char) tolower(str[i]); - } -} - -void dedupe_hyphenated(char *out, char *str, struct tokenset *pTokenset) { - char *tok; - while ((tok = strsep(&str, "-")) != NULL) { - if (has_token(pTokenset, tok)) { - continue; - } - add_token(pTokenset, tok); - if (strlen(out) > 0) { - strcat(out, "-"); - } - strcat(out, tok); - } -} - -int is_unique_path_element(char *path_element) { - if (strlen(path_element) == 0) { - return 0; - } - - static const char *standard_path_parts[] = {"usr", "local", "bin", "home", "etc", "lib", "opt", ".."}; - static const int num_standard_path_parts = 8; - for (int i = 0; i < num_standard_path_parts; ++i) { - const char *part = standard_path_parts[i]; - if (strcmp(part, path_element) == 0) { - return 0; - } - } - return 1; -} - -// removes a .jar suffix/extension from a string if it's long enough -void truncate_extension(char *str) { - unsigned long len = strlen(str); - if (len <= 4) { - return; - } - if (strstr(str + len - 4, ".jar")) { - str[len - 4] = 0; - } -} - -int is_legal_java_main_class_with_module(const char *str) { - int num_slashes = 0; - int num_dots = 0; - for (int i = 0; str[i] != 0; ++i) { - if (str[i] == '.') { - ++num_dots; - } - if (str[i] == '/') { - ++num_slashes; - } - } - if (num_dots == 0) { - return 0; - } - if (num_slashes == 0) { - return is_legal_java_main_class(str); - } else if (num_slashes > 1) { - return 0; - } - char *fq_main_package = strdup(str); - char *module = strsep(&fq_main_package, "/"); - - if (!is_legal_java_main_class(fq_main_package)) { - return 0; - } - - if (!is_legal_module(module)) { - return 0; - } - - return 1; -} - -int is_legal_java_main_class(const char *str) { - if (strstr(str, ".") == NULL) { - return 0; - } - char *dup = strdup(str); - char *prev; - while (1) { - char *token = strsep(&dup, "."); - if (token == NULL) { - return is_capital_letter(prev[0]); - } - if (!is_legal_java_package_element(token)) { - return 0; - } - prev = token; - } -} - -int is_capital_letter(const char ch) { - return ch >= 'A' && ch <= 'Z'; -} - -int is_legal_module(char *module) { - char *dup = strdup(module); - char *token; - while ((token = strsep(&dup, ".")) != NULL) { - if (!is_legal_java_package_element(token)) { - return 0; - } - } - return 1; -} - -// tests if the parts between the dots in e.g. some.package.MyMain are legal -int is_legal_java_package_element(const char *str) { - for (int i = 0;; ++i) { - char ch = str[i]; - if (ch == 0) { - break; - } - if (i == 0 && ch >= '0' && ch <= '9') { - return 0; - } - if (ch < '0' || (ch > '9' && ch < 'A') || (ch > 'Z' && ch < '_') || ch == '`' || ch > 'z') { - return 0; - } - } - return 1; -} diff --git a/instrumentation/src/args.h b/instrumentation/src/args.h deleted file mode 100644 index 9e0f5557d7..0000000000 --- a/instrumentation/src/args.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef INSTRUMENTATION_ARGS_H -#define INSTRUMENTATION_ARGS_H - -#include "cmdline_reader.h" -#include "logger.h" - -#define TOKENSET_MAX_SIZE 256 - -struct tokenset { - int i; - char *tokens[TOKENSET_MAX_SIZE]; -}; - -void init_tokenset(struct tokenset *tks); - -void free_tokenset(struct tokenset *tks); - -int has_token(struct tokenset *tks, char *token); - -void add_token(struct tokenset *tks, char *token); - -int get_cmdline_args(char **args, cmdline_reader cr, int max_args, int max_cmdline_len, logger log); - -void free_cmdline_args(char **args, int num_args); - -void generate_servicename_from_args(char *dest, char **args, int num_args); - -int is_legal_java_main_class(const char *str); - -int is_capital_letter(char ch); - -int is_legal_java_main_class_with_module(const char *str); - -int is_legal_module(char *module); - -int is_legal_java_package_element(const char *str); - -void transform_multi_jars(char *dest, char *arg, struct tokenset *tks); - -void transform_jar_path_elements(char *out, char *path); - -void dedupe_hyphenated(char *out, char *str, struct tokenset *pTokenset); - -int is_unique_path_element(char *path_element); - -void truncate_extension(char *str); - -void format_arg(char *str); - -#endif //INSTRUMENTATION_ARGS_H diff --git a/instrumentation/src/cmdline_reader.c b/instrumentation/src/cmdline_reader.c deleted file mode 100644 index 8255ef4fff..0000000000 --- a/instrumentation/src/cmdline_reader.c +++ /dev/null @@ -1,38 +0,0 @@ -#include "cmdline_reader.h" -#include -#include -#include - -struct cmdline_reader_impl { - FILE *f; -}; - -cmdline_reader new_cmdline_reader() { - cmdline_reader cr = malloc(sizeof(cmdline_reader)); - if (cr != NULL) { - cr->f = NULL; - } - return cr; -} - -void cmdline_reader_open(cmdline_reader cr) { - pid_t pid = getpid(); - char fname[1024]; - sprintf(fname, "/proc/%d/cmdline", pid); - cr->f = fopen(fname, "r"); -} - -int cmdline_reader_is_eof(cmdline_reader cr) { - return feof(cr->f) != 0; -} - -char cmdline_reader_get_char(cmdline_reader cr) { - return (char) fgetc(cr->f); -} - -void cmdline_reader_close(cmdline_reader cr) { - if (cr->f != NULL) { - fclose(cr->f); - } - free(cr); -} diff --git a/instrumentation/src/cmdline_reader.h b/instrumentation/src/cmdline_reader.h deleted file mode 100644 index 2aba64dd01..0000000000 --- a/instrumentation/src/cmdline_reader.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef INSTRUMENTATION_CMDLINE_READER_H -#define INSTRUMENTATION_CMDLINE_READER_H - -typedef struct cmdline_reader_impl *cmdline_reader; -cmdline_reader new_cmdline_reader(); -cmdline_reader new_test_cmdline_reader(char *cmdline, int len); -void cmdline_reader_open(cmdline_reader cr); -int cmdline_reader_is_eof(cmdline_reader cr); -char cmdline_reader_get_char(cmdline_reader cr); -void cmdline_reader_close(cmdline_reader cr); - -#endif //INSTRUMENTATION_CMDLINE_READER_H diff --git a/instrumentation/src/cmdline_reader_test.c b/instrumentation/src/cmdline_reader_test.c deleted file mode 100644 index 512e4b7c20..0000000000 --- a/instrumentation/src/cmdline_reader_test.c +++ /dev/null @@ -1,44 +0,0 @@ -#include "cmdline_reader.h" -#include -#include -#include - -struct cmdline_reader_impl { - int i; - unsigned long size; - char *cmdline; -}; - -cmdline_reader new_cmdline_reader() { - // It appears that just having the - // void __attribute__((constructor)) splunk_instrumentation_enter() - // function in the executable causes it to run during tests, so we - // create a cmdline_reader here. - return new_test_cmdline_reader("", 0); -} - -cmdline_reader new_test_cmdline_reader(char *cmdline, int size) { - cmdline_reader cr = malloc(sizeof(*cr)); - cr->i = 0; - - cr->cmdline = malloc(size); - memcpy(cr->cmdline, cmdline, size); - - cr->size = size; - return cr; -} - -void cmdline_reader_open(cmdline_reader cr) { -} - -int cmdline_reader_is_eof(cmdline_reader cr) { - return cr->i >= cr->size; -} - -char cmdline_reader_get_char(cmdline_reader cr) { - return cr->cmdline[cr->i++]; -} - -void cmdline_reader_close(cmdline_reader cr) { - free(cr->cmdline); -} diff --git a/instrumentation/src/config.c b/instrumentation/src/config.c deleted file mode 100644 index c34f00797c..0000000000 --- a/instrumentation/src/config.c +++ /dev/null @@ -1,126 +0,0 @@ -#include -#include -#include -#include "config.h" -#include "splunk.h" - -struct kv { - char *k; - char *v; -}; - -void read_config_file(logger log, struct config *cfg, char *file_name); - -void read_lines(struct config *cfg, FILE *fp); - -void split_on_eq(char *string, struct kv *pair); - -void log_config_field(logger log, const char *field, const char *value); - -void load_config(logger log, struct config *cfg, char *file_name) { - read_config_file(log, cfg, file_name); - log_config_field(log, "service_name", cfg->service_name); - log_config_field(log, "java_agent_jar", cfg->java_agent_jar); - log_config_field(log, "resource_attributes", cfg->resource_attributes); - log_config_field(log, "disable_telemetry", cfg->disable_telemetry); - log_config_field(log, "generate_service_name", cfg->generate_service_name); - log_config_field(log, "enable_profiler", cfg->enable_profiler); - log_config_field(log, "enable_profiler_memory", cfg->enable_profiler_memory); - log_config_field(log, "enable_metrics", cfg->enable_metrics); -} - -void log_config_field(logger log, const char *field, const char *value) { - char msg[MAX_LOG_LINE_LEN] = ""; - if (value == NULL) { - snprintf(msg, MAX_LOG_LINE_LEN, "config: %s not specified", field); - } else { - snprintf(msg, MAX_LOG_LINE_LEN, "config: %s=%s", field, value); - } - log_debug(log, msg); -} - -void read_config_file(logger log, struct config *cfg, char *file_name) { - FILE *fp = fopen(file_name, "r"); - char log_line[MAX_LOG_LINE_LEN]; - if (fp == NULL) { - strcpy(log_line, "file not found: "); - strncat(log_line, file_name, MAX_LOG_LINE_LEN - strlen(log_line) - 1); - log_debug(log, log_line); - return; - } - - strcpy(log_line, "reading config file: "); - strncat(log_line, file_name, MAX_LOG_LINE_LEN - strlen(log_line) - 1); - log_debug(log, log_line); - read_lines(cfg, fp); - fclose(fp); -} - -void read_lines(struct config *cfg, FILE *fp) { - static const int buflen = 255; - char buf[buflen]; - struct kv pair = {.k = NULL, .v = NULL}; - while ((fgets(buf, buflen, fp)) != NULL) { - buf[strcspn(buf, "\n")] = 0; - split_on_eq(buf, &pair); - if (streq(pair.k, "java_agent_jar")) { - cfg->java_agent_jar = strdup(pair.v); - } else if (streq(pair.k, "service_name")) { - cfg->service_name = strdup(pair.v); - } else if (streq(pair.k, "resource_attributes")) { - cfg->resource_attributes = strdup(pair.v); - } else if (streq(pair.k, "disable_telemetry")) { - cfg->disable_telemetry = strdup(pair.v); - } else if (streq(pair.k, "generate_service_name")) { - cfg->generate_service_name = strdup(pair.v); - } else if (streq(pair.k, "enable_profiler")) { - cfg->enable_profiler = strdup(pair.v); - } else if (streq(pair.k, "enable_profiler_memory")) { - cfg->enable_profiler_memory = strdup(pair.v); - } else if (streq(pair.k, "enable_metrics")) { - cfg->enable_metrics = strdup(pair.v); - } - } -} - -void split_on_eq(char *string, struct kv *pair) { - pair->k = strsep(&string, "="); - pair->v = string; -} - -int str_to_bool(char *v, int defaultVal) { - if (v == NULL) { - return defaultVal; - } - if (streq("false", v) || streq("FALSE", v) || streq("0", v)) { - return 0; - } - return 1; -} - -void free_config(struct config *cfg) { - if (cfg->java_agent_jar != NULL) { - free(cfg->java_agent_jar); - } - if (cfg->service_name != NULL) { - free(cfg->service_name); - } - if (cfg->resource_attributes != NULL) { - free(cfg->resource_attributes); - } - if (cfg->disable_telemetry != NULL) { - free(cfg->disable_telemetry); - } - if (cfg->generate_service_name != NULL) { - free(cfg->generate_service_name); - } - if (cfg->enable_profiler != NULL) { - free(cfg->enable_profiler); - } - if (cfg->enable_profiler_memory != NULL) { - free(cfg->enable_profiler_memory); - } - if (cfg->enable_metrics != NULL) { - free(cfg->enable_metrics); - } -} diff --git a/instrumentation/src/config.h b/instrumentation/src/config.h deleted file mode 100644 index c384a11e51..0000000000 --- a/instrumentation/src/config.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef INSTRUMENTATION_CONFIG_H -#define INSTRUMENTATION_CONFIG_H - -#include "logger.h" - -struct config { - char *java_agent_jar; - char *service_name; - char *resource_attributes; - char *disable_telemetry; - char *generate_service_name; - char *enable_profiler; - char *enable_profiler_memory; - char *enable_metrics; -}; - -void load_config(logger log, struct config *cfg, char *file_name); - -int str_to_bool(char *v, int); - -void free_config(struct config *cfg); - -#endif //INSTRUMENTATION_CONFIG_H diff --git a/instrumentation/src/logger.c b/instrumentation/src/logger.c deleted file mode 100644 index 3d20e59b8a..0000000000 --- a/instrumentation/src/logger.c +++ /dev/null @@ -1,29 +0,0 @@ -#include -#include -#include "logger.h" - -static char *const prefix = "splunk-instrumentation: %s"; - -struct logger_impl { -}; - -logger new_logger() { - logger out = malloc(sizeof *out); - return out; -} - -void log_debug(logger l, char *s) { - syslog(LOG_DEBUG, prefix, s); -} - -void log_info(logger l, char *s) { - syslog(LOG_INFO, prefix, s); -} - -void log_warning(logger l, char *s) { - syslog(LOG_WARNING, prefix, s); -} - -void free_logger(logger l) { - free(l); -} diff --git a/instrumentation/src/logger.h b/instrumentation/src/logger.h deleted file mode 100644 index 1e483fb3fc..0000000000 --- a/instrumentation/src/logger.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef SPLUNK_INSTRUMENTATION_LOGGER_H -#define SPLUNK_INSTRUMENTATION_LOGGER_H - -#define MAX_LOG_LINE_LEN 1024 - -typedef struct logger_impl *logger; - -logger new_logger(); - -void log_debug(logger l, char *s); - -void log_info(logger l, char *s); - -void log_warning(logger l, char *s); - -int get_logs(logger l, char **buf); - -void free_logger(logger l); - -#endif //SPLUNK_INSTRUMENTATION_LOGGER_H diff --git a/instrumentation/src/main.c b/instrumentation/src/main.c new file mode 100644 index 0000000000..074e02bfb6 --- /dev/null +++ b/instrumentation/src/main.c @@ -0,0 +1,103 @@ +#include +#include +#include +#include + +#define MAX_LINE_LENGTH 1023 +#define MAX_LINES 50 + +#define ALLOWED_ENV_VARS "OTEL_SERVICE_NAME", "OTEL_EXPORTER_OTLP_ENDPOINT", "OTEL_RESOURCE_ATTRIBUTES", "SPLUNK_PROFILER_ENABLED", "SPLUNK_PROFILER_MEMORY_ENABLED", "SPLUNK_METRICS_ENABLED", "JAVA_TOOL_OPTIONS", "NODE_OPTIONS" + +static char *const allowed_env_vars[] = {ALLOWED_ENV_VARS}; +static size_t const allowed_env_vars_size = sizeof(allowed_env_vars) / sizeof(*allowed_env_vars); + +#define JAVA_ENV_VAR_FILE "/etc/splunk/zeroconfig_java.conf" +#define NODEJS_ENV_VAR_FILE "/etc/splunk/zeroconfig_node.conf" + +// TODO change to systemd drop in file paths +static char *const env_var_file_java = JAVA_ENV_VAR_FILE; +static char *const env_var_file_node = NODEJS_ENV_VAR_FILE; + +extern char *program_invocation_short_name; + +// The entry point for all executables prior to their execution. +void __attribute__((constructor)) enter() { + char *env_var_file; + if (strcmp("java", program_invocation_short_name) == 0) { + env_var_file = env_var_file_java; + } else if (strcmp("node", program_invocation_short_name) == 0) { + env_var_file = env_var_file_node; + } else { + // we don't want to inject environment variables for this program. + return; + } + + if (MAX_LINES <= 0 || MAX_LINE_LENGTH <= 0) { + return; + } + + const size_t buffer_size = MAX_LINE_LENGTH + 1; + char buffer[buffer_size]; + + FILE *fp = fopen(env_var_file, "r"); + if (fp == NULL) { + return; + } + + int line_count = 0; + + while (fgets(buffer, buffer_size, fp) != NULL) { + line_count += 1; + if (line_count > MAX_LINES) { + break; + } + + char *newline = memchr(buffer, '\n', buffer_size); + if (newline != NULL) { + // terminate the string inside buffer at the newline + *newline = '\0'; + } + // if we have read a string without a newline termination, we have reached the end of file + // or the string is past our max buffer size and we have an invalid value and we need to abort. + + // Properly formatted input file contains lines of length less than MAX_LINE_LENGTH and ends with a newline. + // If newline character is not read, it means that a line is greater that MAX_LINE_LENGTH or the file does not end with a newline. + if (newline == NULL) { + break; + } + if (strnlen(buffer, buffer_size) == 0) { + continue; + } + if (buffer[0] == '#') { + continue; + } + + char *equals = memchr(buffer, '=', buffer_size); + if (equals == NULL) { + continue; + } + + // buffer is key=value\0 + + *equals = '\0'; + + // buffer is key\0value\0 + + char *key = buffer; + char *value = equals + 1; + + // check if key is allowed: + if (strchr(key, ' ') != NULL) { + continue; + } + + // check if key is allowed + for (int i = 0; i < allowed_env_vars_size; i++) { + if (strcmp(allowed_env_vars[i], key) == 0) { + setenv(key, value, 0); + break; + } + } + } + fclose(fp); +} diff --git a/instrumentation/src/metrics_client.c b/instrumentation/src/metrics_client.c deleted file mode 100644 index 3130e0dfc4..0000000000 --- a/instrumentation/src/metrics_client.c +++ /dev/null @@ -1,133 +0,0 @@ -#include "metrics_client.h" - -#include -#include -#include -#include -#include -#include - -static const int RECV_BUF_LEN = 1024; - -static const int METRIC_JSON_MAX_LEN = 1024; - -static char *const expected = "HTTP/1.1 200 OK"; - -int http_post(char *host, int port, char *method, char *path, char *postData, logger pImpl); - -int make_socket(int timeout_seconds); - -int connect_http(const char *host, int port, int socket_descriptor); - -int post(int socket_descriptor, char *host, int port, char *method, char *path, char *postData); - -int receive(int socket_descriptor); - -int mk_metrics_json(char *dest, int max_len, char *service_name); - -void send_otlp_metric(logger log, char *service_name) { - char json[METRIC_JSON_MAX_LEN]; - int len = mk_metrics_json(json, METRIC_JSON_MAX_LEN, service_name); - if (len == METRIC_JSON_MAX_LEN - 1) { - log_debug(log, "otlp metric json too long, not sending"); - return; - } - char *host = "127.0.0.1"; - int port = 4318; - char *method = "POST"; - char *path = "/v1/metrics"; - if (http_post(host, port, method, path, json, log)) { - log_debug(log, "send otlp metric succeeded"); - } else { - log_debug(log, "send otlp metric failed"); - } -} - -int mk_metrics_json(char *dest, int max_len, char *service_name) { - char *format = "{\"resourceMetrics\":[{\"resource\":{},\"scopeMetrics\":[{\"scope\":{},\"metrics\":" - "[{\"name\":\"splunk.linux-autoinstr.executions\",\"sum\":{\"dataPoints\":" - "[{\"attributes\":[{\"key\":\"service.name\",\"value\":{\"stringValue\":\"%s\"}}],\"asInt\":\"1\"}]," - "\"aggregationTemporality\":\"AGGREGATION_TEMPORALITY_DELTA\"}}]}]}]}"; - return snprintf(dest, max_len, format, service_name); -} - -int http_post(char *host, int port, char *method, char *path, char *postData, logger log) { - int socket_descriptor = make_socket(1); - if (socket_descriptor == -1) { - log_debug(log, "metrics client failed to open socket"); - return 0; - } - - if (!connect_http(host, port, socket_descriptor)) { - log_debug(log, "metrics client failed to connect"); - return 0; - } - - if (!post(socket_descriptor, host, port, method, path, postData)) { - log_debug(log, "metrics client failed to send"); - return 0; - } - - if (!receive(socket_descriptor)) { - log_debug(log, "metrics client failed to receive response"); - return 0; - } - - return 1; -} - -int make_socket(int timeout_seconds) { - int socket_descriptor = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); - if (socket_descriptor == -1) { - return -1; - } - - struct timeval timeout; - timeout.tv_sec = timeout_seconds; - timeout.tv_usec = 0; - - if (setsockopt(socket_descriptor, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) { - return -1; - } - - if (setsockopt(socket_descriptor, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) < 0) { - return -1; - } - - return socket_descriptor; -} - -int connect_http(const char *host, int port, int socket_descriptor) { - struct sockaddr_in address; - address.sin_family = AF_INET; - address.sin_addr.s_addr = inet_addr(host); - address.sin_port = htons(port); - int errno = connect(socket_descriptor, (struct sockaddr *) &address, sizeof(address)); - return errno == 0; -} - -int post(int socket_descriptor, char *host, int port, char *method, char *path, char *postData) { - char *req_pattern = "%s %s HTTP/1.1\n" - "Host: %s:%d\n" - "Content-Type: application/json\n" - "Content-Length: %d\n" - "User-Agent: splunk-zc/1.0\n" - "Accept: */*\n\n%s"; - char req_str[1024]; - sprintf(req_str, req_pattern, method, path, host, port, strlen(postData), postData); - - size_t req_len = strlen(req_str); - ssize_t num_bytes_sent = send(socket_descriptor, req_str, req_len, 0); - return num_bytes_sent == req_len; -} - -int receive(int socket_descriptor) { - char buf[RECV_BUF_LEN]; - ssize_t recv_size = recv(socket_descriptor, buf, RECV_BUF_LEN, 0); - size_t expected_len = strlen(expected); - if (recv_size < expected_len) { - return 0; - } - - return strncmp(expected, buf, expected_len) == 0; -} diff --git a/instrumentation/src/metrics_client.h b/instrumentation/src/metrics_client.h deleted file mode 100644 index e43a348949..0000000000 --- a/instrumentation/src/metrics_client.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef INSTRUMENTATION_METRICS_CLIENT_H -#define INSTRUMENTATION_METRICS_CLIENT_H - -#include "logger.h" - -typedef void (*send_otlp_metric_func_t)(logger, char *); - -void send_otlp_metric(logger, char *); - -#endif //INSTRUMENTATION_METRICS_CLIENT_H diff --git a/instrumentation/src/splunk.c b/instrumentation/src/splunk.c deleted file mode 100644 index fa456f5248..0000000000 --- a/instrumentation/src/splunk.c +++ /dev/null @@ -1,239 +0,0 @@ -#include "splunk.h" -#include "config.h" -#include "metrics_client.h" -#include "args.h" - -#include -#include -#include -#include - -#define MAX_ENV_VAR_LEN 512 -#define MAX_CONFIG_ATTR_LEN 256 -#define MAX_CMDLINE_LEN 16000 -#define MAX_ARGS 256 - -#define JAVA_TOOL_OPTIONS_PREFIX "-javaagent:"; - -static char *const conf_file = "/usr/lib/splunk-instrumentation/instrumentation.conf"; -static char *const prof_enabled_cmdline_switch = " -Dsplunk.profiler.enabled=true"; -static char *const prof_memory_enabled_cmdline_switch = " -Dsplunk.profiler.memory.enabled=true"; -static char *const metrics_enabled_cmdline_switch = " -Dsplunk.metrics.enabled=true"; - -extern char *program_invocation_short_name; - -int has_read_access(const char *s); - -void set_java_tool_options(logger log, struct config *cfg); - -void get_service_name_from_cmdline(logger log, char *dest, cmdline_reader cr); - -int is_disable_env_set(); - -int is_java_tool_options_set(); - -void set_env_var(logger log, const char *var_name, const char *value); - -void set_env_var_from_attr(logger log, const char *attr_name, const char *env_var_name, const char *value); - -void get_service_name(logger log, cmdline_reader cr, struct config *cfg, char *dest); - -void log_line_length_warning(logger log, char *log_line); - -// The entry point for all executables prior to their execution. If the executable is named "java", we -// set the env vars JAVA_TOOL_OPTIONS to the path of the java agent jar and OTEL_SERVICE_NAME to the -// service name based on the arguments to the java command. -void __attribute__((constructor)) splunk_instrumentation_enter() { - logger l = new_logger(); - cmdline_reader cr = new_cmdline_reader(); - if (cr == NULL) { - return; - } - auto_instrument(l, has_read_access, program_invocation_short_name, load_config, cr, send_otlp_metric); - cmdline_reader_close(cr); - free_logger(l); -} - -void auto_instrument( - logger log, - has_access_func_t has_access, - const char *program_name, - load_config_func_t load_config_func, - cmdline_reader cr, - send_otlp_metric_func_t send_otlp_metric_func -) { - if (!streq(program_name, "java")) { - return; - } - if (is_disable_env_set()) { - log_debug(log, "disable_env set, quitting"); - return; - } - if (is_java_tool_options_set()) { - log_debug(log, "java_tool_options set, quitting"); - return; - } - - struct config cfg = { - .java_agent_jar = NULL, - .resource_attributes = NULL, - .service_name = NULL, - .disable_telemetry = NULL, - .generate_service_name = NULL, - .enable_profiler = NULL, - .enable_profiler_memory = NULL, - .enable_metrics = NULL - }; - load_config_func(log, &cfg, conf_file); - if (cfg.java_agent_jar == NULL) { - log_warning(log, "java_agent_jar not set, quitting"); - return; - } - - if (!has_access(cfg.java_agent_jar)) { - log_info(log, "agent jar not found or no read access, quitting"); - return; - } - - char service_name[MAX_CMDLINE_LEN] = ""; - if (str_to_bool(cfg.generate_service_name, 1)) { - get_service_name(log, cr, &cfg, service_name); - if (strlen(service_name) == 0) { - log_info(log, "service name empty, quitting"); - return; - } - set_env_var(log, otel_service_name_var, service_name); - } else { - log_debug(log, "service name generation explicitly disabled"); - } - - set_java_tool_options(log, &cfg); - - set_env_var_from_attr(log, "resource_attributes", resource_attributes_var, cfg.resource_attributes); - - if (str_to_bool(cfg.disable_telemetry, 0)) { - log_info(log, "disabling telemetry as per config"); - } else { - send_otlp_metric_func(log, service_name); - } - - free_config(&cfg); -} - -void get_service_name(logger log, cmdline_reader cr, struct config *cfg, char *dest) { - if (cfg->service_name == NULL) { - get_service_name_from_cmdline(log, dest, cr); - } else { - strncpy(dest, (*cfg).service_name, MAX_CMDLINE_LEN); - } -} - -void get_service_name_from_cmdline(logger log, char *dest, cmdline_reader cr) { - char *args[MAX_ARGS]; - int n = get_cmdline_args(args, cr, MAX_ARGS, MAX_CMDLINE_LEN, log); - generate_servicename_from_args(dest, args, n); - free_cmdline_args(args, n); -} - -void set_env_var_from_attr(logger log, const char *attr_name, const char *env_var_name, const char *value) { - if (value == NULL) { - return; - } - size_t len = strlen(value); - if (len > MAX_CONFIG_ATTR_LEN) { - char log_line[MAX_LOG_LINE_LEN] = ""; - sprintf(log_line, "%s too long: got %zu chars, max %d chars", attr_name, len, MAX_CONFIG_ATTR_LEN); - log_warning(log, log_line); - return; - } - set_env_var(log, env_var_name, value); -} - -void set_env_var(logger log, const char *var_name, const char *value) { - char log_line[MAX_LOG_LINE_LEN] = ""; - sprintf(log_line, "setting %s='%s'", var_name, value); - log_debug(log, log_line); - setenv(var_name, value, 0); -} - -void set_java_tool_options(logger log, struct config *cfg) { - char java_tool_options[MAX_ENV_VAR_LEN] = JAVA_TOOL_OPTIONS_PREFIX; - char log_line[MAX_LOG_LINE_LEN] = ""; - size_t jar_path_len = strlen(cfg->java_agent_jar); - if (jar_path_len > MAX_CONFIG_ATTR_LEN) { - sprintf(log_line, "jar_path too long: got %zu chars, max %d chars", jar_path_len, MAX_CONFIG_ATTR_LEN); - log_warning(log, log_line); - return; - } - int remaining = concat_strings(java_tool_options, cfg->java_agent_jar, MAX_ENV_VAR_LEN); - // It's not possible (at time of writing) for `remaining` to be less than zero in this function because the sum of - // MAX_CONFIG_ATTR_LEN (256) and the lengths of the pre-defined command line switches will always be less than - // MAX_ENV_VAR_LEN (512), but check for truncation anyway to account for future additions. - if (remaining < 0) { - log_line_length_warning(log, log_line); - return; - } - if (str_to_bool(cfg->enable_profiler, 0)) { - remaining = concat_strings(java_tool_options, prof_enabled_cmdline_switch, MAX_ENV_VAR_LEN); - if (remaining < 0) { - log_line_length_warning(log, log_line); - return; - } - } - if (str_to_bool(cfg->enable_profiler_memory, 0)) { - remaining = concat_strings(java_tool_options, prof_memory_enabled_cmdline_switch, MAX_ENV_VAR_LEN); - if (remaining < 0) { - log_line_length_warning(log, log_line); - return; - } - } - if (str_to_bool(cfg->enable_metrics, 0)) { - remaining = concat_strings(java_tool_options, metrics_enabled_cmdline_switch, MAX_ENV_VAR_LEN); - if (remaining < 0) { - log_line_length_warning(log, log_line); - return; - } - } - sprintf(log_line, "setting JAVA_TOOL_OPTIONS='%s'", java_tool_options); - log_debug(log, log_line); - setenv(java_tool_options_var, java_tool_options, 0); -} - -void log_line_length_warning(logger log, char *log_line) { - sprintf(log_line, "excessive line length: not setting JAVA_TOOL_OPTIONS"); - log_warning(log, log_line); -} - -// concat_strings concatenates the string defined by src to the memory location pointed to by dest, -// returning the number of characters remaining in the dest buffer. The return value may be negative -// indicating the number of characters that were not concatenated because of a lack of space. The tot_dest_size -// argument indicates the total number of bytes in the dest memory array. See unit tests for examples. -int concat_strings(char *dest, char *src, int tot_dest_size) { - int orig_dest_len = (int) strlen(dest); - strncat(dest, src, tot_dest_size - 1); - return tot_dest_size - (int) orig_dest_len - (int) strlen(src) - 1; -} - -int is_disable_env_set() { - char *env = getenv(disable_env_var); - return env && !streq("false", env) && !streq("FALSE", env) && !streq("0", env); -} - -int is_java_tool_options_set() { - char *env = getenv(java_tool_options_var); - return env != NULL && strlen(env) > 0; -} - -int has_read_access(const char *s) { - return access(s, R_OK) == 0; -} - -int streq(const char *expected, const char *actual) { - if (expected == NULL && actual == NULL) { - return 1; - } - if (expected == NULL || actual == NULL) { - return 0; - } - return strcmp(expected, actual) == 0; -} diff --git a/instrumentation/src/splunk.h b/instrumentation/src/splunk.h deleted file mode 100644 index 0f17279f86..0000000000 --- a/instrumentation/src/splunk.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef SPLUNK_INSTRUMENTATION_SPLUNK_H -#define SPLUNK_INSTRUMENTATION_SPLUNK_H - -#include "logger.h" -#include "config.h" -#include "cmdline_reader.h" -#include "metrics_client.h" - -static char *const disable_env_var = "DISABLE_SPLUNK_AUTOINSTRUMENTATION"; -static char *const java_tool_options_var = "JAVA_TOOL_OPTIONS"; -static char *const otel_service_name_var = "OTEL_SERVICE_NAME"; -static char *const resource_attributes_var = "OTEL_RESOURCE_ATTRIBUTES"; - -typedef int (*has_access_func_t)(const char *); - -typedef void (*load_config_func_t)(logger log, struct config *, char *); - -void auto_instrument( - logger log, - has_access_func_t has_access, - const char *program_name, - load_config_func_t load_config_func, - cmdline_reader cr, - send_otlp_metric_func_t send_otlp_metric_func -); - -int streq(const char *expected, const char *actual); - -int concat_strings(char *dest, char *src, int tot_dest_size); - -#endif //SPLUNK_INSTRUMENTATION_SPLUNK_H diff --git a/instrumentation/src/test_logger.c b/instrumentation/src/test_logger.c deleted file mode 100644 index 585c1af162..0000000000 --- a/instrumentation/src/test_logger.c +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include -#include "logger.h" - -struct logger_impl { - int i; - char *logs[MAX_LOG_LINE_LEN]; -}; - -logger new_logger() { - logger l = malloc(sizeof *l); - if (l) { - l->i = 0; - } - return l; -} - -void save_log(logger l, char *s) { - l->logs[l->i++] = strdup(s); -} - -void log_info(logger l, char *s) { - save_log(l, s); -} - -void log_debug(logger l, char *s) { - save_log(l, s); -} - -void log_warning(logger l, char *s) { - save_log(l, s); -} - -void free_logger(logger l) { - for (int i = 0; i < l->i; ++i) { - free(l->logs[i]); - } - free(l); -} - -int get_logs(logger l, char *buf[]) { - for (int i = 0; i < l->i; ++i) { - buf[i] = l->logs[i]; - } - return l->i; -} diff --git a/instrumentation/src/test_main.c b/instrumentation/src/test_main.c deleted file mode 100644 index 4bab4bca75..0000000000 --- a/instrumentation/src/test_main.c +++ /dev/null @@ -1,1056 +0,0 @@ -#include "test_main.h" -#include "splunk.h" -#include "config.h" -#include "args.h" -#include "test_utils.h" -#include -#include -#include - -static char *const test_config_path = "testdata/instrumentation-default.conf"; -static char *const test_config_path_all_options = "testdata/instrumentation-options.conf"; - -int main(void) { - run_tests(); - puts("PASS"); - return EXIT_SUCCESS; -} - -void run_tests() { - test_func_t *tests[] = { - test_auto_instrument_svc_name_specified, - test_auto_instrument_gen_svc_name_explicitly_enabled, - test_auto_instrument_gen_svc_name_explicitly_disabled, - test_auto_instrument_no_svc_name_in_config, - test_auto_instrument_not_java, - test_auto_instrument_no_access, - test_auto_instrument_splunk_env_var_true, - test_auto_instrument_splunk_env_var_false, - test_auto_instrument_splunk_env_var_false_caps, - test_auto_instrument_splunk_env_var_zero, - test_read_config_default, - test_read_config_all_options, - test_read_config_missing_file, - test_read_args_simple, - test_read_args_max_args_limit, - test_read_args_max_cmdline_len_limit, - test_transform_jar_path_elements, - test_dedupe_hyphenated, - test_truncate_jar, - test_truncate_jar_short, - test_is_unique_path_element, - test_transform_multi_jars, - test_tokenset, - test_tokenset_overflow, - test_extract_servicename_from_args_tomcat, - test_extract_servicename_from_args_simple_jar, - test_extract_servicename_from_args_module, - test_extract_servicename_from_args_okhttp, - test_extract_servicename_from_args_zk, - test_extract_servicename_from_args_kafka, - test_extract_servicename_from_args_spring, - test_dots_to_dashes, - test_env_var_already_set, - test_is_legal_java_package_element, - test_is_legal_java_fq_main_class, - test_is_legal_java_module_main_class, - test_is_legal_module, - test_str_to_bool, - test_disable_telemetry, - test_enable_telemetry, - test_enable_profiling, - test_enable_profiling_memory, - test_enable_metrics, - test_concat_string_to_empty_just_enough_room, - test_concat_string_to_empty_extra_room, - test_concat_string_to_empty_not_enough_room, - test_concat_string_to_nonempty_just_enough_room, - test_long_cfg_attributes, - test_auto_instrument_gen_svcname_disabled_but_specified - }; - for (int i = 0; i < sizeof tests / sizeof tests[0]; ++i) { - run_test(tests[i]); - } -} - -void run_test(test_func_t run_test) { - unsetenv(java_tool_options_var); - unsetenv(otel_service_name_var); - unsetenv(resource_attributes_var); - unsetenv(disable_env_var); - logger l = new_logger(); - run_test(l); - free_logger(l); -} - -void test_auto_instrument_svc_name_specified(logger l) { - cmdline_reader cr = new_default_test_cmdline_reader(); - auto_instrument(l, access_check_true, "java", fake_config_svcname_explicitly_specified, cr, - fake_send_otlp_metric); - char *logs[256]; - int n = get_logs(l, logs); - - char *funcname = "test_auto_instrument_svc_name_specified"; - require_equal_ints(funcname, 4, n); - require_equal_strings(funcname, "setting OTEL_SERVICE_NAME='my.override'", logs[0]); - require_equal_strings(funcname, "setting JAVA_TOOL_OPTIONS='-javaagent:/foo/asdf.jar'", logs[1]); - require_equal_strings(funcname, "setting OTEL_RESOURCE_ATTRIBUTES='myattr=myval'", logs[2]); - require_equal_strings(funcname, "sending metric", logs[3]); - require_env(funcname, "-javaagent:/foo/asdf.jar", java_tool_options_var); - require_env(funcname, "my.override", otel_service_name_var); - cmdline_reader_close(cr); -} - -void test_auto_instrument_gen_svc_name_explicitly_enabled(logger l) { - char *funcname = "test_auto_instrument_gen_svc_name_explicitly_enabled"; - cmdline_reader cr = new_default_test_cmdline_reader(); - auto_instrument(l, access_check_true, "java", fake_config_generate_svcname_enabled, cr, fake_send_otlp_metric); - char *logs[256]; - int n = get_logs(l, logs); - require_equal_strings(funcname, "setting OTEL_SERVICE_NAME='foo'", logs[0]); - require_equal_strings(funcname, "setting JAVA_TOOL_OPTIONS='-javaagent:/foo/asdf.jar'", logs[1]); - require_equal_strings(funcname, "setting OTEL_RESOURCE_ATTRIBUTES='myattr=myval'", logs[2]); - require_equal_strings(funcname, "sending metric", logs[3]); - require_equal_ints(funcname, 4, n); - require_env(funcname, "foo", otel_service_name_var); -} - -void test_auto_instrument_gen_svc_name_explicitly_disabled(logger l) { - char *funcname = "test_auto_instrument_gen_svc_name_explicitly_disabled"; - cmdline_reader cr = new_default_test_cmdline_reader(); - auto_instrument(l, access_check_true, "java", fake_config_generate_svcname_disabled, cr, fake_send_otlp_metric); - char *logs[256]; - int n = get_logs(l, logs); - require_equal_strings(funcname, "service name generation explicitly disabled", logs[0]); - require_equal_strings(funcname, "setting JAVA_TOOL_OPTIONS='-javaagent:/foo/asdf.jar'", logs[1]); - require_equal_strings(funcname, "sending metric", logs[2]); - require_equal_ints(funcname, 3, n); - require_unset_env(funcname, otel_service_name_var); -} - -void test_auto_instrument_gen_svcname_disabled_but_specified(logger l) { - char *funcname = "test_auto_instrument_gen_svcname_disabled_but_specified"; - cmdline_reader cr = new_default_test_cmdline_reader(); - auto_instrument(l, access_check_true, "java", fake_config_generate_svcname_disabled_but_explicitly_specified, cr, fake_send_otlp_metric); - char *logs[256]; - int n = get_logs(l, logs); - require_equal_strings(funcname, "service name generation explicitly disabled", logs[0]); - require_equal_strings(funcname, "setting JAVA_TOOL_OPTIONS='-javaagent:/foo/asdf.jar'", logs[1]); - require_equal_strings(funcname, "sending metric", logs[2]); - require_equal_ints(funcname, 3, n); - require_unset_env(funcname, otel_service_name_var); -} - -void test_auto_instrument_no_svc_name_in_config(logger l) { - cmdline_reader cr = new_default_test_cmdline_reader(); - auto_instrument(l, access_check_true, "java", fake_config_no_svcname, cr, fake_send_otlp_metric); - char *logs[256]; - int n = get_logs(l, logs); - char *funcname = "test_auto_instrument_no_svc_name_in_config"; - require_equal_ints(funcname, 3, n); - require_equal_strings(funcname, "setting OTEL_SERVICE_NAME='foo'", logs[0]); - require_equal_strings(funcname, "setting JAVA_TOOL_OPTIONS='-javaagent:/foo/asdf.jar'", logs[1]); - require_equal_strings(funcname, "sending metric", logs[2]); - require_env(funcname, "-javaagent:/foo/asdf.jar", java_tool_options_var); - require_env(funcname, "foo", otel_service_name_var); - cmdline_reader_close(cr); -} - -void test_auto_instrument_not_java(logger l) { - cmdline_reader cr = new_default_test_cmdline_reader(); - auto_instrument(l, access_check_true, "foo", fake_config_svcname_explicitly_specified, cr, - fake_send_otlp_metric); - char *funcname = "test_auto_instrument_not_java"; - require_unset_env(funcname, java_tool_options_var); - char *logs[256]; - int n = get_logs(l, logs); - require_equal_ints(funcname, 0, n); - cmdline_reader_close(cr); -} - -void test_auto_instrument_no_access(logger l) { - cmdline_reader cr = new_default_test_cmdline_reader(); - auto_instrument(l, access_check_false, "java", fake_config_svcname_explicitly_specified, cr, - fake_send_otlp_metric); - require_unset_env("test_auto_instrument_no_access", java_tool_options_var); - char *logs[256]; - char *funcname = "test_auto_instrument_no_access"; - require_equal_ints(funcname, 1, get_logs(l, logs)); - require_equal_strings(funcname, "agent jar not found or no read access, quitting", logs[0]); - cmdline_reader_close(cr); -} - -void test_auto_instrument_splunk_env_var_true(logger l) { - setenv(disable_env_var, "true", 0); - cmdline_reader cr = new_default_test_cmdline_reader(); - auto_instrument(l, access_check_true, "java", fake_config_svcname_explicitly_specified, cr, - fake_send_otlp_metric); - require_unset_env("test_auto_instrument_splunk_env_var_true", "JAVA_TOOL_OPTIONS"); - cmdline_reader_close(cr); -} - -void test_auto_instrument_splunk_env_var_false(logger l) { - setenv(disable_env_var, "false", 0); - cmdline_reader cr = new_default_test_cmdline_reader(); - auto_instrument(l, access_check_true, "java", fake_config_svcname_explicitly_specified, cr, - fake_send_otlp_metric); - require_env("test_auto_instrument_splunk_env_var_false", "-javaagent:/foo/asdf.jar", "JAVA_TOOL_OPTIONS"); - cmdline_reader_close(cr); -} - -void test_auto_instrument_splunk_env_var_false_caps(logger l) { - setenv(disable_env_var, "FALSE", 0); - cmdline_reader cr = new_default_test_cmdline_reader(); - auto_instrument(l, access_check_true, "java", fake_config_svcname_explicitly_specified, cr, - fake_send_otlp_metric); - require_env("test_auto_instrument_splunk_env_var_false_caps", "-javaagent:/foo/asdf.jar", "JAVA_TOOL_OPTIONS"); - cmdline_reader_close(cr); -} - -void test_auto_instrument_splunk_env_var_zero(logger l) { - setenv(disable_env_var, "0", 0); - cmdline_reader cr = new_default_test_cmdline_reader(); - auto_instrument(l, access_check_true, "java", fake_config_svcname_explicitly_specified, cr, fake_send_otlp_metric); - require_env("test_auto_instrument_splunk_env_var_zero", "-javaagent:/foo/asdf.jar", "JAVA_TOOL_OPTIONS"); - cmdline_reader_close(cr); -} - -void test_read_config_default(logger l) { - struct config cfg = {.java_agent_jar = NULL, .service_name = NULL}; - load_config(l, &cfg, test_config_path); - char *logs[256]; - int n = get_logs(l, logs); - char *funcname = "test_read_config_default"; - require_equal_ints(funcname, 9, n); - require_equal_strings(funcname, "reading config file: testdata/instrumentation-default.conf", logs[0]); - require_equal_strings(funcname, "config: service_name not specified", logs[1]); - require_equal_strings(funcname, "config: java_agent_jar=/usr/lib/splunk-instrumentation/splunk-otel-javaagent.jar", logs[2]); - require_equal_strings(funcname, "config: resource_attributes=deployment.environment=test", logs[3]); - require_equal_strings(funcname, "config: disable_telemetry not specified", logs[4]); - require_equal_strings(funcname, "config: generate_service_name not specified", logs[5]); - require_equal_strings(funcname, "config: enable_profiler not specified", logs[6]); - require_equal_strings(funcname, "config: enable_profiler_memory not specified", logs[7]); - require_equal_strings(funcname, "config: enable_metrics not specified", logs[8]); - require_equal_strings(funcname, "/usr/lib/splunk-instrumentation/splunk-otel-javaagent.jar", cfg.java_agent_jar); - require_equal_strings(funcname, NULL, cfg.service_name); - require_equal_strings(funcname, "deployment.environment=test", cfg.resource_attributes); - require_equal_strings(funcname, NULL, cfg.disable_telemetry); - require_equal_strings(funcname, NULL, cfg.generate_service_name); - require_equal_strings(funcname, NULL, cfg.enable_profiler); - require_equal_strings(funcname, NULL, cfg.enable_profiler_memory); - require_equal_strings(funcname, NULL, cfg.enable_metrics); - free_config(&cfg); -} - -void test_read_config_all_options(logger l) { - struct config cfg = {.java_agent_jar = NULL, .service_name = NULL}; - load_config(l, &cfg, test_config_path_all_options); - char *logs[256]; - int n = get_logs(l, logs); - char *funcname = "test_read_config_all_options"; - require_equal_ints(funcname, 9, n); - require_equal_strings(funcname, "reading config file: testdata/instrumentation-options.conf", logs[0]); - require_equal_strings(funcname, "config: service_name=default.service", logs[1]); - require_equal_strings(funcname, "config: java_agent_jar=/usr/lib/splunk-instrumentation/splunk-otel-javaagent.jar", logs[2]); - require_equal_strings(funcname, "config: resource_attributes=deployment.environment=test", logs[3]); - require_equal_strings(funcname, "config: disable_telemetry=true", logs[4]); - require_equal_strings(funcname, "config: generate_service_name=true", logs[5]); - require_equal_strings(funcname, "config: enable_profiler=true", logs[6]); - require_equal_strings(funcname, "config: enable_profiler_memory=true", logs[7]); - require_equal_strings(funcname, "config: enable_metrics=true", logs[8]); - - require_equal_strings(funcname, "default.service", cfg.service_name); - require_equal_strings(funcname, "/usr/lib/splunk-instrumentation/splunk-otel-javaagent.jar", cfg.java_agent_jar); - require_equal_strings(funcname, "deployment.environment=test", cfg.resource_attributes); - require_equal_strings(funcname, "true", cfg.disable_telemetry); - require_equal_strings(funcname, "true", cfg.generate_service_name); - require_equal_strings(funcname, "true", cfg.enable_profiler); - require_equal_strings(funcname, "true", cfg.enable_profiler_memory); - require_equal_strings(funcname, "true", cfg.enable_metrics); - free_config(&cfg); -} - -void test_read_config_missing_file(logger l) { - struct config cfg = {.java_agent_jar = NULL, .service_name = NULL}; - load_config(l, &cfg, "foo.txt"); - char *logs[256]; - int n = get_logs(l, logs); - char *funcname = "test_read_config_missing_file"; - require_equal_ints(funcname, 9, n); - require_equal_strings(funcname, "file not found: foo.txt", logs[0]); - require_equal_strings(funcname, "config: service_name not specified", logs[1]); - require_equal_strings(funcname, "config: java_agent_jar not specified", logs[2]); - require_equal_strings(funcname, "config: resource_attributes not specified", logs[3]); - require_equal_strings(funcname, "config: disable_telemetry not specified", logs[4]); - require_equal_strings(funcname, "config: generate_service_name not specified", logs[5]); - require_equal_strings(funcname, "config: enable_profiler not specified", logs[6]); - require_equal_strings(funcname, "config: enable_profiler_memory not specified", logs[7]); - require_equal_strings(funcname, "config: enable_metrics not specified", logs[8]); - require_equal_strings(funcname, NULL, cfg.service_name); - require_equal_strings(funcname, NULL, cfg.java_agent_jar); - free_config(&cfg); -} - -void test_read_args_simple(logger l) { - cmdline_reader cr = new_default_test_cmdline_reader(); - char *args[4]; - int n = get_cmdline_args(args, cr, 3, 128, NULL); - char *funcname = "test_read_args_simple"; - require_equal_ints(funcname, 3, n); - char *expected[] = {"java", "-jar", "foo.jar"}; - for (int i = 0; i < n; ++i) { - require_equal_strings(funcname, expected[i], args[i]); - } - free_cmdline_args(args, n); - cmdline_reader_close(cr); -} - -void test_read_args_max_args_limit(logger l) { - cmdline_reader cr = new_default_test_cmdline_reader(); - char *args[1]; // not big enough! - int n = get_cmdline_args(args, cr, 1, 128, NULL); - char *funcname = "test_read_args_max_args_limit"; - require_equal_ints(funcname, 1, n); - require_equal_strings(funcname, "java", args[0]); - free_cmdline_args(args, n); - cmdline_reader_close(cr); -} - -void test_read_args_max_cmdline_len_limit(logger l) { - cmdline_reader cr = new_default_test_cmdline_reader(); - int max_args = 16; - char *args[max_args]; - int max_cmdline_len = 8; - int n = get_cmdline_args(args, cr, max_args, max_cmdline_len, l); - char *funcname = "test_read_args_max_cmdline_len_limit"; - require_equal_ints(funcname, 1, n); - require_equal_strings(funcname, "java", args[0]); - free_cmdline_args(args, n); - cmdline_reader_close(cr); -} - -void test_is_unique_path_element(logger l) { - require_true("test_is_unique_path_element", !is_unique_path_element("usr")); - require_true("test_is_unique_path_element", !is_unique_path_element("bin")); - require_true("test_is_unique_path_element", is_unique_path_element("foo")); -} - -void test_truncate_jar(logger l) { - char *jar_part = strdup("foo.jar"); - truncate_extension(jar_part); - require_equal_strings("test_truncate_jar", "foo", jar_part); - free(jar_part); -} - -void test_truncate_jar_short(logger l) { - char *jar_part = strdup(".jar"); - truncate_extension(jar_part); - require_equal_strings("test_truncate_jar", ".jar", jar_part); - free(jar_part); -} - -void test_transform_jar_path_elements(logger l) { - char path_buf[4096] = ""; - transform_jar_path_elements(path_buf, strdup("/usr/local/APACHE-TOMCAT/8.5.4/bin/apache-tomcat.jar")); - char *funcname = "test_clean_jar_path_elements"; - require_equal_strings(funcname, "apache-tomcat-8.5.4-apache-tomcat", path_buf); -} - -void test_dedupe_hyphenated(logger l) { - char hyphen_buf[4096] = ""; - struct tokenset tks; - init_tokenset(&tks); - dedupe_hyphenated(hyphen_buf, strdup("apache-tomcat-8.5.4-apache-tomcat"), &tks); - require_equal_strings("test_dedupe_hyphenated", "apache-tomcat-8.5.4", hyphen_buf); - free_tokenset(&tks); -} - -void test_transform_multi_jars(logger l) { - char *arg = "/usr/local/apache-tomcat/8.5.4/bin/bootstrap.jar:/usr/local/apache-tomcat/8.5.4/bin/tomcat-juli.jar"; - char transformed[4096] = ""; - struct tokenset tks; - init_tokenset(&tks); - transform_multi_jars(transformed, strdup(arg), &tks); - require_equal_strings( - "test_transform_multi_jars", - "apache-tomcat-8.5.4-bootstrap-juli", - transformed - ); - free_tokenset(&tks); -} - -void test_tokenset(logger l) { - struct tokenset tks; - init_tokenset(&tks); - char *funcname = "test_tokenset"; - - require_false(funcname, has_token(&tks, "foo")); - add_token(&tks, "foo"); - require_true(funcname, has_token(&tks, "foo")); - add_token(&tks, "foo"); - require_true(funcname, has_token(&tks, "foo")); - - require_false(funcname, has_token(&tks, "bar")); - add_token(&tks, "bar"); - require_true(funcname, has_token(&tks, "bar")); - require_false(funcname, has_token(&tks, "baz")); - add_token(&tks, "baz"); - require_true(funcname, has_token(&tks, "baz")); - add_token(&tks, "baz"); - require_true(funcname, has_token(&tks, "baz")); - free_tokenset(&tks); -} - -void test_tokenset_overflow(logger l) { - struct tokenset tks; - init_tokenset(&tks); - char *funcname = "test_tokenset_overflow"; - for (int i = 1; i < TOKENSET_MAX_SIZE; ++i) { - char buf[8]; - sprintf(buf, "tok-%d", i); - require_false(funcname, has_token(&tks, buf)); - add_token(&tks, buf); - } - free_tokenset(&tks); -} - -void test_extract_servicename_from_args_tomcat(logger l) { - char *args[32]; - int num_args = tomcat_args(args); - char service_name[4096] = ""; - generate_servicename_from_args(service_name, args, num_args); - require_equal_strings( - "test_extract_servicename_from_args_tomcat", - "org-apache-catalina-startup-bootstrap", - service_name - ); -} - -void test_extract_servicename_from_args_simple_jar(logger l) { - char *args[32]; - int num_args = petclinic_args(args); - char service_name[4096] = ""; - generate_servicename_from_args(service_name, args, num_args); - require_equal_strings( - "test_extract_servicename_from_args_simple_jar", - "app-spring-petclinic-2.4.5", - service_name - ); -} - -void test_extract_servicename_from_args_module(logger l) { - char *args[32]; - int num_args = module_args(args); - char service_name[4096] = ""; - generate_servicename_from_args(service_name, args, num_args); - require_equal_strings("test_extract_servicename_from_args_module", "com-mymodule-com-myorg-main", service_name); -} - -void test_extract_servicename_from_args_okhttp(logger l) { - char *args[32]; - int num_args = okhttp_and_jedis_args(args); - char service_name[4096] = ""; - generate_servicename_from_args(service_name, args, num_args); - require_equal_strings( - "test_extract_servicename_from_args_module", - "target-java-agent-example-1.0-snapshot-shaded", - service_name - ); -} - -void test_extract_servicename_from_args_zk(logger l) { - char *args[32]; - int num_args = zk_args(args); - char service_name[8192] = ""; - generate_servicename_from_args(service_name, args, num_args); - require_equal_strings( - "test_extract_servicename_from_args_zk", - "org-apache-zookeeper-server-quorum-quorumpeermain", - service_name - ); -} - -void test_extract_servicename_from_args_kafka(logger l) { - char *args[32]; - int num_args = kafka_args(args); - char service_name[8192] = ""; - generate_servicename_from_args(service_name, args, num_args); - require_equal_strings( - "test_extract_servicename_from_args_kafka", - "kafka-kafka", - service_name - ); -} - -void test_extract_servicename_from_args_spring(logger l) { - char *args[32]; - int num_args = spring_args(args); - char service_name[8192] = ""; - generate_servicename_from_args(service_name, args, num_args); - require_equal_strings( - "test_extract_servicename_from_args_spring", - "com-example-demo-demoapplication", - service_name - ); -} - -void test_dots_to_dashes(logger l) { - char *str = strdup("aaa.bbb.ccc"); - format_arg(str); - require_equal_strings("test_dots_to_dashes", "aaa-bbb-ccc", str); -} - -void test_env_var_already_set(logger l) { - setenv("JAVA_TOOL_OPTIONS", "hello", 0); - cmdline_reader cr = new_default_test_cmdline_reader(); - auto_instrument(l, access_check_true, "java", fake_config_svcname_explicitly_specified, cr, - fake_send_otlp_metric); - char *funcname = "test_env_var_already_set"; - require_env(funcname, "hello", java_tool_options_var); - cmdline_reader_close(cr); -} - -void test_is_legal_java_package_element(logger l) { - char *funcname = "test_is_legal_java_package_element"; - require_true(funcname, is_legal_java_package_element("zookeeper")); - require_true(funcname, is_legal_java_package_element("has_underscores_42")); - require_false(funcname, is_legal_java_package_element("has:colon")); - require_false(funcname, is_legal_java_package_element("has/slash")); - require_false(funcname, is_legal_java_package_element("has-dash")); - require_false(funcname, is_legal_java_package_element("1_starts_with_number")); -} - -void test_is_legal_java_module_main_class(logger l) { - char *funcname = "is_legal_java_main_class_with_module"; - require_true(funcname, is_legal_java_main_class_with_module("com.my_module/com.myorg.Main")); - require_true(funcname, is_legal_java_main_class_with_module("com.myorg.Main")); - require_false(funcname, is_legal_java_main_class_with_module("http://my_module/com.myorg.Main")); -} - -void test_is_legal_java_fq_main_class(logger l) { - char *funcname = "test_is_legal_java_fq_main_class"; - require_true(funcname, is_legal_java_main_class("org.apache.zookeeper.server.quorum.QuorumPeerMain")); - require_false(funcname, is_legal_java_main_class("org.apache.zookeeper.server.quorum.quorumPeerMain")); - require_false(funcname, is_legal_java_main_class("org.apache.zookeeper-server.quorum.QuorumPeerMain")); - require_false(funcname, is_legal_java_main_class("Main")); - require_false(funcname, is_legal_java_main_class("http://google.com")); -} - -void test_is_legal_module(logger l) { - char *funcname = "test_is_legal_module"; - require_true(funcname, is_legal_module("foo.bar")); - require_true(funcname, is_legal_module("bar")); - require_false(funcname, is_legal_module("foo/bar")); - require_false(funcname, is_legal_module("foo bar")); -} - -void test_str_to_bool(logger l) { - require_false("test_str_bool", str_to_bool("false", 0)); - require_false("test_str_bool", str_to_bool("FALSE", 0)); - require_false("test_str_bool", str_to_bool("0", 0)); - require_false("test_str_bool", str_to_bool(NULL, 0)); - require_true("test_str_bool", str_to_bool("true", 0)); - require_true("test_str_bool", str_to_bool("42", 0)); - require_true("test_str_bool", str_to_bool(NULL, 1)); -} - -void test_enable_telemetry(logger l) { - cmdline_reader cr = new_default_test_cmdline_reader(); - auto_instrument(l, access_check_true, "java", fake_config_disable_telemetry_not_specified, cr, - fake_send_otlp_metric); - char *logs[256]; - get_logs(l, logs); - require_equal_strings("test_enable_telemetry", "sending metric", logs[2]); -} - -void test_disable_telemetry(logger l) { - cmdline_reader cr = new_default_test_cmdline_reader(); - auto_instrument(l, access_check_true, "java", fake_config_disable_telemetry_true, cr, fake_send_otlp_metric); - char *logs[256]; - get_logs(l, logs); - require_equal_strings("test_disable_telemetry", "disabling telemetry as per config", logs[2]); -} - -void test_enable_profiling(logger l) { - cmdline_reader cr = new_default_test_cmdline_reader(); - auto_instrument(l, access_check_true, "java", fake_config_enable_profiler, cr, fake_send_otlp_metric); - require_env("test_enable_profiling", "-javaagent:/foo/asdf.jar -Dsplunk.profiler.enabled=true", "JAVA_TOOL_OPTIONS"); -} - -void test_enable_profiling_memory(logger l) { - cmdline_reader cr = new_default_test_cmdline_reader(); - auto_instrument(l, access_check_true, "java", fake_config_enable_profiler_memory, cr, fake_send_otlp_metric); - require_env("test_enable_profiling_memory", "-javaagent:/foo/asdf.jar -Dsplunk.profiler.memory.enabled=true", "JAVA_TOOL_OPTIONS"); -} - -void test_enable_metrics(logger l) { - cmdline_reader cr = new_default_test_cmdline_reader(); - auto_instrument(l, access_check_true, "java", fake_config_enable_metrics, cr, fake_send_otlp_metric); - require_env("test_enable_metrics", "-javaagent:/foo/asdf.jar -Dsplunk.metrics.enabled=true", "JAVA_TOOL_OPTIONS"); -} - -void test_concat_string_to_empty_just_enough_room(logger l) { - char *funcname = "test_concat_string_to_empty_just_enough_room"; - char dest[4] = ""; - int res = concat_strings(dest, "abc", 4); - require_equal_ints(funcname, 0, res); - require_equal_strings(funcname, "abc", dest); -} - -void test_concat_string_to_empty_extra_room(logger l) { - char *funcname = "test_concat_string_to_empty_extra_room"; - char dest[8] = ""; - int res = concat_strings(dest, "abc", 8); - require_equal_ints(funcname, 4, res); - require_equal_strings(funcname, "abc", dest); -} - -void test_concat_string_to_empty_not_enough_room(logger l) { - char *funcname = "test_concat_string_to_empty_not_enough_room"; - char dest[2] = ""; - int res = concat_strings(dest, "abc", 2); - require_equal_ints(funcname, -2, res); - require_equal_strings(funcname, "a", dest); -} - -void test_concat_string_to_nonempty_just_enough_room(logger l) { - char *funcname = "test_concat_string_to_nonempty_just_enough_room"; - char dest[4] = "ab"; - int res = concat_strings(dest, "c", 4); - require_equal_ints(funcname, 0, res); - require_equal_strings(funcname, "abc", dest); -} - -void test_long_cfg_attributes(logger l) { - cmdline_reader cr = new_default_test_cmdline_reader(); - auto_instrument(l, access_check_true, "java", fake_config_max_attributes, cr, fake_send_otlp_metric); - require_env_len("test_long_cfg_attributes", 255, "OTEL_SERVICE_NAME"); - require_env_len("test_long_cfg_attributes", 365, "JAVA_TOOL_OPTIONS"); - require_env_len("test_long_cfg_attributes", 255, "OTEL_RESOURCE_ATTRIBUTES"); -} - -// fakes/testdata - -void fake_send_otlp_metric(logger log, char *service_name) { - log_debug(log, "sending metric"); -} - -void fake_config_svcname_explicitly_specified(logger log, struct config *cfg, char *path) { - cfg->java_agent_jar = strdup("/foo/asdf.jar"); - cfg->service_name = strdup("my.override"); - cfg->resource_attributes = strdup("myattr=myval"); - cfg->disable_telemetry = strdup("false"); -} - -void fake_config_generate_svcname_enabled(logger log, struct config *cfg, char *path) { - cfg->java_agent_jar = strdup("/foo/asdf.jar"); - cfg->resource_attributes = strdup("myattr=myval"); - cfg->disable_telemetry = strdup("false"); - cfg->generate_service_name = strdup("true"); -} - -void fake_config_generate_svcname_disabled(logger log, struct config *cfg, char *path) { - cfg->java_agent_jar = strdup("/foo/asdf.jar"); - cfg->generate_service_name = strdup("false"); -} - -void fake_config_generate_svcname_disabled_but_explicitly_specified(logger log, struct config *cfg, char *path) { - cfg->java_agent_jar = strdup("/foo/asdf.jar"); - cfg->generate_service_name = strdup("false"); - cfg->service_name = strdup("my-explicit-servicename"); -} - -void fake_config_no_svcname(logger log, struct config *cfg, char *path) { - cfg->java_agent_jar = strdup("/foo/asdf.jar"); -} - -void fake_config_disable_telemetry_not_specified(logger log, struct config *cfg, char *path) { - cfg->java_agent_jar = strdup("/foo/asdf.jar"); -} - -void fake_config_disable_telemetry_true(logger log, struct config *cfg, char *path) { - cfg->java_agent_jar = strdup("/foo/asdf.jar"); - cfg->disable_telemetry = strdup("true"); -} - -void fake_config_enable_profiler(logger log, struct config *cfg, char *path) { - cfg->java_agent_jar = strdup("/foo/asdf.jar"); - cfg->enable_profiler = strdup("true"); -} - -void fake_config_enable_profiler_memory(logger log, struct config *cfg, char *path) { - cfg->java_agent_jar = strdup("/foo/asdf.jar"); - cfg->enable_profiler_memory = strdup("true"); -} - -void fake_config_enable_metrics(logger log, struct config *cfg, char *path) { - cfg->java_agent_jar = strdup("/foo/asdf.jar"); - cfg->enable_metrics = strdup("true"); -} - -void fake_config_max_attributes(logger log, struct config *cfg, char *path) { - char *str_255 = "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" - "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" - "1234567890123456789012345678901234567890123456789012345"; - cfg->java_agent_jar = strdup(str_255); - cfg->service_name = strdup(str_255); - cfg->resource_attributes = strdup(str_255); - cfg->enable_profiler = strdup("true"); - cfg->enable_profiler_memory = strdup("true"); - cfg->enable_metrics = strdup("true"); -} - -cmdline_reader new_default_test_cmdline_reader() { - char cmdline[] = {'j', 'a', 'v', 'a', 0, '-', 'j', 'a', 'r', 0, 'f', 'o', 'o', '.', 'j', 'a', 'r', 0}; - return new_test_cmdline_reader(cmdline, sizeof(cmdline)); -} - -int access_check_true(const char *s) { - return 1; -} - -int access_check_false(const char *s) { - return 0; -} - -int tomcat_args(char *args[]) { - int n = 0; - args[n++] = "java"; - args[n++] = "-Djava.util.logging.config.file=/usr/local/apache-tomcat/8.5.4/conf/logging.properties"; - args[n++] = "-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager"; - args[n++] = "-Djdk.tls.ephemeralDHKeySize=2048"; - args[n++] = "-classpath"; - args[n++] = "/usr/local/apache-tomcat/8.5.4/bin/bootstrap.jar:/usr/local/apache-tomcat/8.5.4/bin/tomcat-juli.jar"; - args[n++] = "-Dcatalina.base=/usr/local/apache-tomcat/8.5.4"; - args[n++] = "-Dcatalina.home=/usr/local/apache-tomcat/8.5.4"; - args[n++] = "-Djava.io.tmpdir=/usr/local/apache-tomcat/8.5.4/temp"; - args[n++] = "org.apache.catalina.startup.Bootstrap"; - args[n++] = "start"; - for (int i = 0; i < n; ++i) { - args[i] = strdup(args[i]); - } - return n; -} - -int petclinic_args(char *args[]) { - int n = 0; - args[n++] = "/usr/bin/java"; - args[n++] = "-cp"; - args[n++] = "my/classpath"; - args[n++] = "-jar"; - args[n++] = "app/spring-petclinic-2.4.5.jar"; - for (int i = 0; i < n; ++i) { - args[i] = strdup(args[i]); - } - return n; -} - -int module_args(char *args[]) { - int n = 0; - args[n++] = "/usr/bin/java"; - args[n++] = "--module-path"; - args[n++] = "mods"; - args[n++] = "-m"; - args[n++] = "com.mymodule/com.myorg.Main"; - for (int i = 0; i < n; ++i) { - args[i] = strdup(args[i]); - } - return n; -} - -int okhttp_and_jedis_args(char *args[]) { - int n = 0; - args[n++] = "java"; - args[n++] = "-jar"; - args[n++] = "target/java-agent-example-1.0-SNAPSHOT-shaded.jar"; - args[n++] = "https://google.com"; - for (int i = 0; i < n; ++i) { - args[i] = strdup(args[i]); - } - return n; -} - -int zk_args(char *args[]) { - int n = 0; - args[n++] = "java"; - args[n++] = "-Xmx512M"; - args[n++] = "-Xms512M"; - args[n++] = "-server"; - args[n++] = "-XX:+UseG1GC"; - args[n++] = "-XX:MaxGCPauseMillis=20"; - args[n++] = "-XX:InitiatingHeapOccupancyPercent=35"; - args[n++] = "-XX:+ExplicitGCInvokesConcurrent"; - args[n++] = "-XX:MaxInlineLevel=15"; - args[n++] = "-Djava.awt.headless=true"; - args[n++] = "-Xlog:gc*:file=/usr/local/kafka/kafka_2.13-3.1.0/bin/../logs/zookeeper-gc.log:time,tags:filecount=10,filesize=100M"; - args[n++] = "-Dcom.sun.management.jmxremote"; - args[n++] = "-Dcom.sun.management.jmxremote.authenticate=false"; - args[n++] = "-Dcom.sun.management.jmxremote.ssl=false"; - args[n++] = "-Dkafka.logs.dir=/usr/local/kafka/kafka_2.13-3.1.0/bin/../logs"; - args[n++] = "-Dlog4j.configuration=file:bin/../config/log4j.properties"; - args[n++] = "-cp"; - args[n++] = zk_classpath(); - args[n++] = "org.apache.zookeeper.server.quorum.QuorumPeerMain"; - args[n++] = "config/zookeeper.properties"; - for (int i = 0; i < n; ++i) { - args[i] = strdup(args[i]); - } - return n; -} - -char *zk_classpath() { - return "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/activation-1.1.1.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/aopalliance-repackaged-2.6.1.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/argparse4j-0.7.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/audience-annotations-0.5.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/commons-cli-1.4.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/commons-lang3-3.8.1.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/connect-api-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/connect-basic-auth-extension-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/connect-file-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/connect-json-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/connect-mirror-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/connect-mirror-client-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/connect-runtime-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/connect-transforms-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/hk2-api-2.6.1.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/hk2-locator-2.6.1.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/hk2-utils-2.6.1.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jackson-annotations-2.12.3.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jackson-core-2.12.3.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jackson-databind-2.12.3.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jackson-dataformat-csv-2.12.3.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jackson-datatype-jdk8-2.12.3.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jackson-jaxrs-base-2.12.3.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jackson-jaxrs-json-provider-2.12.3.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jackson-module-jaxb-annotations-2.12.3.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jackson-module-scala_2.13-2.12.3.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jakarta.activation-api-1.2.1.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jakarta.annotation-api-1.3.5.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jakarta.inject-2.6.1.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jakarta.validation-api-2.0.2.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jakarta.ws.rs-api-2.1.6.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jakarta.xml.bind-api-2.3.2.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/javassist-3.27.0-GA.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/javax.servlet-api-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/javax.ws.rs-api-2.1.1.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jaxb-api-2.3.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jersey-client-2.34.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jersey-common-2.34.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jersey-container-servlet-2.34.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jersey-container-servlet-core-2.34.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jersey-hk2-2.34.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jersey-server-2.34.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jetty-client-9.4.43.v20210629.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jetty-continuation-9.4.43.v20210629.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jetty-http-9.4.43.v20210629.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jetty-io-9.4.43.v20210629.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jetty-security-9.4.43.v20210629.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jetty-server-9.4.43.v20210629.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jetty-servlet-9.4.43.v20210629.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jetty-servlets-9.4.43.v20210629.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jetty-util-9.4.43.v20210629.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jetty-util-ajax-9.4.43.v20210629.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jline-3.12.1.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jopt-simple-5.0.4.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jose4j-0.7.8.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/kafka_2.13-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/kafka-clients-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/kafka-log4j-appender-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/kafka-metadata-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/kafka-raft-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/kafka-server-common-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/kafka-shell-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/kafka-storage-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/kafka-storage-api-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/kafka-streams-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/kafka-streams-examples-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/kafka-streams-scala_2.13-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/kafka-streams-test-utils-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/kafka-tools-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/log4j-1.2.17.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/lz4-java-1.8.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/maven-artifact-3.8.1.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/metrics-core-2.2.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/metrics-core-4.1.12.1.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/netty-buffer-4.1.68.Final.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/netty-codec-4.1.68.Final.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/netty-common-4.1.68.Final.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/netty-handler-4.1.68.Final.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/netty-resolver-4.1.68.Final.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/netty-transport-4.1.68.Final.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/netty-transport-native-epoll-4.1.68.Final.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/netty-transport-native-unix-common-4.1.68.Final.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/osgi-resource-locator-1.0.3.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/paranamer-2.8.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/plexus-utils-3.2.1.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/reflections-0.9.12.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/rocksdbjni-6.22.1.1.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/scala-collection-compat_2.13-2.4.4.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/scala-java8-compat_2.13-1.0.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/scala-library-2.13.6.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/scala-logging_2.13-3.9.3.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/scala-reflect-2.13.6.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/slf4j-api-1.7.30.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/slf4j-log4j12-1.7.30.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/snappy-java-1.1.8.4.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/trogdor-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/zookeeper-3.6.3.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/zookeeper-jute-3.6.3.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/zstd-jni-1.5.0-4.jar"; -} - -int kafka_args(char *args[]) { - int n = 0; - args[n++] = "java"; - args[n++] = "-Xmx1G"; - args[n++] = "-Xms1G"; - args[n++] = "-server"; - args[n++] = "-XX:+UseG1GC"; - args[n++] = "-XX:MaxGCPauseMillis=20"; - args[n++] = "-XX:InitiatingHeapOccupancyPercent=35"; - args[n++] = "-XX:+ExplicitGCInvokesConcurrent"; - args[n++] = "-XX:MaxInlineLevel=15"; - args[n++] = "-Djava.awt.headless=true"; - args[n++] = "-Xlog:gc*:file=/usr/local/kafka/kafka_2.13-3.1.0/bin/../logs/kafkaServer-gc.log:time,tags:filecount=10,filesize=100M"; - args[n++] = "-Dcom.sun.management.jmxremote"; - args[n++] = "-Dcom.sun.management.jmxremote.authenticate=false"; - args[n++] = "-Dcom.sun.management.jmxremote.ssl=false"; - args[n++] = "-Dkafka.logs.dir=/usr/local/kafka/kafka_2.13-3.1.0/bin/../logs"; - args[n++] = "-Dlog4j.configuration=file:bin/../config/log4j.properties"; - args[n++] = "-cp"; - args[n++] = "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/activation-1.1.1.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/aopalliance-repackaged-2.6.1.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/argparse4j-0.7.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/audience-annotations-0.5.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/commons-cli-1.4.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/commons-lang3-3.8.1.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/connect-api-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/connect-basic-auth-extension-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/connect-file-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/connect-json-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/connect-mirror-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/connect-mirror-client-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/connect-runtime-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/connect-transforms-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/hk2-api-2.6.1.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/hk2-locator-2.6.1.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/hk2-utils-2.6.1.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jackson-annotations-2.12.3.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jackson-core-2.12.3.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jackson-databind-2.12.3.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jackson-dataformat-csv-2.12.3.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jackson-datatype-jdk8-2.12.3.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jackson-jaxrs-base-2.12.3.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jackson-jaxrs-json-provider-2.12.3.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jackson-module-jaxb-annotations-2.12.3.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jackson-module-scala_2.13-2.12.3.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jakarta.activation-api-1.2.1.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jakarta.annotation-api-1.3.5.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jakarta.inject-2.6.1.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jakarta.validation-api-2.0.2.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jakarta.ws.rs-api-2.1.6.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jakarta.xml.bind-api-2.3.2.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/javassist-3.27.0-GA.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/javax.servlet-api-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/javax.ws.rs-api-2.1.1.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jaxb-api-2.3.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jersey-client-2.34.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jersey-common-2.34.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jersey-container-servlet-2.34.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jersey-container-servlet-core-2.34.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jersey-hk2-2.34.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jersey-server-2.34.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jetty-client-9.4.43.v20210629.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jetty-continuation-9.4.43.v20210629.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jetty-http-9.4.43.v20210629.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jetty-io-9.4.43.v20210629.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jetty-security-9.4.43.v20210629.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jetty-server-9.4.43.v20210629.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jetty-servlet-9.4.43.v20210629.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jetty-servlets-9.4.43.v20210629.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jetty-util-9.4.43.v20210629.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jetty-util-ajax-9.4.43.v20210629.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jline-3.12.1.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jopt-simple-5.0.4.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/jose4j-0.7.8.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/kafka_2.13-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/kafka-clients-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/kafka-log4j-appender-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/kafka-metadata-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/kafka-raft-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/kafka-server-common-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/kafka-shell-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/kafka-storage-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/kafka-storage-api-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/kafka-streams-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/kafka-streams-examples-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/kafka-streams-scala_2.13-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/kafka-streams-test-utils-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/kafka-tools-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/log4j-1.2.17.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/lz4-java-1.8.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/maven-artifact-3.8.1.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/metrics-core-2.2.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/metrics-core-4.1.12.1.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/netty-buffer-4.1.68.Final.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/netty-codec-4.1.68.Final.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/netty-common-4.1.68.Final.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/netty-handler-4.1.68.Final.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/netty-resolver-4.1.68.Final.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/netty-transport-4.1.68.Final.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/netty-transport-native-epoll-4.1.68.Final.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/netty-transport-native-unix-common-4.1.68.Final.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/osgi-resource-locator-1.0.3.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/paranamer-2.8.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/plexus-utils-3.2.1.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/reflections-0.9.12.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/rocksdbjni-6.22.1.1.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/scala-collection-compat_2.13-2.4.4.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/scala-java8-compat_2.13-1.0.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/scala-library-2.13.6.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/scala-logging_2.13-3.9.3.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/scala-reflect-2.13.6.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/slf4j-api-1.7.30.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/slf4j-log4j12-1.7.30.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/snappy-java-1.1.8.4.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/trogdor-3.1.0.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/zookeeper-3.6.3.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/zookeeper-jute-3.6.3.jar:" - "/usr/local/kafka/kafka_2.13-3.1.0/bin/../libs/zstd-jni-1.5.0-4.jar"; - args[n++] = "kafka.Kafka"; - args[n++] = "config/server.properties"; - for (int i = 0; i < n; ++i) { - args[i] = strdup(args[i]); - } - return n; -} - -int spring_args(char *args[]) { - int n = 0; - args[n++] = "java"; - args[n++] = "-cp"; - args[n++] = "/home/pcollins/spring/demo/target/classes:" - "/usr/lib/m2/repository/org/springframework/boot/spring-boot/2.6.7/spring-boot-2.6.7.jar:" - "/usr/lib/m2/repository/org/springframework/spring-context/5.3.19/spring-context-5.3.19.jar:" - "/usr/lib/m2/repository/org/springframework/spring-aop/5.3.19/spring-aop-5.3.19.jar:" - "/usr/lib/m2/repository/org/springframework/spring-beans/5.3.19/spring-beans-5.3.19.jar:" - "/usr/lib/m2/repository/org/springframework/spring-expression/5.3.19/spring-expression-5.3.19.jar:" - "/usr/lib/m2/repository/org/springframework/boot/spring-boot-autoconfigure/2.6.7/spring-boot-autoconfigure-2.6.7.jar:" - "/usr/lib/m2/repository/ch/qos/logback/logback-classic/1.2.11/logback-classic-1.2.11.jar:" - "/usr/lib/m2/repository/ch/qos/logback/logback-core/1.2.11/logback-core-1.2.11.jar:" - "/usr/lib/m2/repository/org/apache/logging/log4j/log4j-to-slf4j/2.17.2/log4j-to-slf4j-2.17.2.jar:" - "/usr/lib/m2/repository/org/apache/logging/log4j/log4j-api/2.17.2/log4j-api-2.17.2.jar:" - "/usr/lib/m2/repository/org/slf4j/jul-to-slf4j/1.7.36/jul-to-slf4j-1.7.36.jar:" - "/usr/lib/m2/repository/jakarta/annotation/jakarta.annotation-api/1.3.5/jakarta.annotation-api-1.3.5.jar:" - "/usr/lib/m2/repository/org/springframework/spring-core/5.3.19/spring-core-5.3.19.jar:" - "/usr/lib/m2/repository/org/springframework/spring-jcl/5.3.19/spring-jcl-5.3.19.jar:" - "/usr/lib/m2/repository/org/yaml/snakeyaml/1.29/snakeyaml-1.29.jar:" - "/usr/lib/m2/repository/org/slf4j/slf4j-api/1.7.36/slf4j-api-1.7.36.jar"; - args[n++] = "com.example.demo.DemoApplication"; - for (int i = 0; i < n; ++i) { - args[i] = strdup(args[i]); - } - return n; -} - diff --git a/instrumentation/src/test_main.h b/instrumentation/src/test_main.h deleted file mode 100644 index f3ad32141a..0000000000 --- a/instrumentation/src/test_main.h +++ /dev/null @@ -1,160 +0,0 @@ -#ifndef SPLUNK_INSTRUMENTATION_TEST_MAIN_H -#define SPLUNK_INSTRUMENTATION_TEST_MAIN_H - -#include "logger.h" -#include "config.h" -#include "cmdline_reader.h" - -typedef void (test_func_t)(logger); - -void run_tests(); - -void run_test(test_func_t run_test); - -void test_auto_instrument_not_java(logger l); - -void test_auto_instrument_svc_name_specified(logger l); - -void test_auto_instrument_gen_svc_name_explicitly_enabled(logger l); - -void test_auto_instrument_gen_svc_name_explicitly_disabled(logger l); - -void test_auto_instrument_no_svc_name_in_config(logger l); - -void test_auto_instrument_no_access(logger l); - -void test_auto_instrument_splunk_env_var_true(logger l); - -void test_auto_instrument_splunk_env_var_false(logger l); - -void test_auto_instrument_splunk_env_var_false_caps(logger l); - -void test_auto_instrument_splunk_env_var_zero(logger l); - -void test_read_config_default(logger l); - -void test_read_config_all_options(logger l); - -void test_read_config_missing_file(logger l); - -void test_read_args_simple(logger l); - -void test_read_args_max_args_limit(logger l); - -void test_read_args_max_cmdline_len_limit(logger l); - -void test_extract_servicename_from_args_tomcat(logger l); - -void test_extract_servicename_from_args_simple_jar(logger l); - -void test_extract_servicename_from_args_module(logger l); - -void test_extract_servicename_from_args_okhttp(logger l); - -void test_extract_servicename_from_args_zk(logger l); - -void test_extract_servicename_from_args_kafka(logger l); - -void test_extract_servicename_from_args_spring(logger l); - -void test_transform_multi_jars(logger l); - -void test_tokenset(logger l); - -void test_tokenset_overflow(logger l); - -void test_transform_jar_path_elements(logger l); - -void test_dedupe_hyphenated(logger l); - -void test_is_unique_path_element(logger l); - -void test_truncate_jar(logger l); - -void test_truncate_jar_short(logger l); - -void test_dots_to_dashes(logger l); - -void test_env_var_already_set(logger l); - -void test_is_legal_java_module_main_class(logger l); - -void test_is_legal_java_fq_main_class(logger l); - -void test_is_legal_java_package_element(logger l); - -void test_is_legal_module(logger l); - -void test_str_to_bool(logger l); - -void test_enable_telemetry(logger l); - -void test_disable_telemetry(logger l); - -void test_enable_profiling(logger l); - -void test_enable_profiling_memory(logger l); - -void test_enable_metrics(logger l); - -void test_concat_string_to_empty_just_enough_room(logger l); - -void test_concat_string_to_empty_extra_room(logger l); - -void test_concat_string_to_empty_not_enough_room(logger l); - -void test_concat_string_to_nonempty_just_enough_room(logger l); - -void test_long_cfg_attributes(logger l); - -void test_auto_instrument_gen_svcname_disabled_but_specified(logger l); - -// fakes/testdata - -void fake_send_otlp_metric(logger log, char *service_name); - -void fake_config_svcname_explicitly_specified(logger log, struct config *cfg, char *path); - -void fake_config_generate_svcname_enabled(logger log, struct config *cfg, char *path); - -void fake_config_generate_svcname_disabled(logger log, struct config *cfg, char *path); - -void fake_config_generate_svcname_disabled_but_explicitly_specified(logger log, struct config *cfg, char *path); - -void fake_config_no_svcname(logger log, struct config *cfg, char *path); - -void fake_config_disable_telemetry_not_specified(logger log, struct config *cfg, char *path); - -void fake_config_disable_telemetry_true(logger log, struct config *cfg, char *path); - -void fake_config_enable_profiler(logger log, struct config *cfg, char *path); - -void fake_config_enable_profiler_memory(logger log, struct config *cfg, char *path); - -void fake_config_enable_metrics(logger log, struct config *cfg, char *path); - -void fake_config_max_attributes(logger log, struct config *cfg, char *path); - -cmdline_reader new_default_test_cmdline_reader(); - -int access_check_true(const char *s); - -int access_check_false(const char *s); - -int tomcat_args(char *args[]); - -int petclinic_args(char *args[]); - -int module_args(char *args[]); - -int okhttp_and_jedis_args(char *args[]); - -int zk_args(char *args[]); - -int kafka_args(char *args[]); - -int spring_args(char *args[]); - -char *zk_classpath(); - -#endif //SPLUNK_INSTRUMENTATION_TEST_MAIN_H diff --git a/instrumentation/src/test_utils.c b/instrumentation/src/test_utils.c deleted file mode 100644 index bdaf57fd01..0000000000 --- a/instrumentation/src/test_utils.c +++ /dev/null @@ -1,68 +0,0 @@ -#include -#include -#include -#include "test_utils.h" -#include "splunk.h" - -void print_logs(char **logs, int n) { - for (int i = 0; i < n; ++i) { - printf("logs[%d]: %s\n", i, logs[i]); - } -} - -void require_true(char *funcname, int actual) { - if (!actual) { - printf("%s: require_true: got false\n", funcname); - fail(); - } -} - -void require_false(char *funcname, int actual) { - if (actual) { - printf("%s: require_false: got true\n", funcname); - fail(); - } -} - -void require_equal_strings(char *funcname, char *expected, char *actual) { - if (!streq(expected, actual)) { - printf("%s: require_equal_strings: expected [%s] got [%s]\n", funcname, expected, actual); - fail(); - } -} - -void require_equal_ints(char *funcname, int expected, int actual) { - if (expected != actual) { - printf("%s: require_equal_ints: expected [%d] got [%d]\n", funcname, expected, actual); - fail(); - } -} - -void require_env(char *funcname, char *expected, char *env_var) { - char *env = getenv(env_var); - if (!streq(expected, env)) { - printf("%s: require_env: %s: expected [%s] got [%s]\n", funcname, env_var, expected, env); - fail(); - } -} - -void require_env_len(char *funcname, int expected_len, char *env_var) { - char *env = getenv(env_var); - size_t env_len = strlen(env); - if (env_len != expected_len) { - printf("%s: require_env_len: %s expected len [%d] got [%d]\n", funcname, env_var, expected_len, (int) env_len); - fail(); - } -} - -void require_unset_env(char *funcname, char *env_var) { - char *env = getenv(env_var); - if (env) { - printf("%s: require_unset_env: %s: expected unset got [%s]\n", funcname, env_var, env); - fail(); - } -} - -void fail() { - exit(EXIT_FAILURE); -} diff --git a/instrumentation/src/test_utils.h b/instrumentation/src/test_utils.h deleted file mode 100644 index 50245dd97d..0000000000 --- a/instrumentation/src/test_utils.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef INSTRUMENTATION_TEST_UTILS_H -#define INSTRUMENTATION_TEST_UTILS_H - -void print_logs(char **logs, int n); - -void require_true(char *funcname, int actual); - -void require_false(char *funcname, int actual); - -void require_equal_strings(char *funcname, char *expected, char *actual); - -void require_equal_ints(char *funcname, int expected, int actual); - -void require_env(char *funcname, char *expected, char *env_var); - -void require_env_len(char *funcname, int expected_len, char *env_var); - -void require_unset_env(char *funcname, char *env_var); - -void fail(); - -#endif //INSTRUMENTATION_TEST_UTILS_H diff --git a/instrumentation/testdata/instrumentation-default.conf b/instrumentation/testdata/instrumentation-default.conf deleted file mode 100644 index a800bad4f4..0000000000 --- a/instrumentation/testdata/instrumentation-default.conf +++ /dev/null @@ -1,2 +0,0 @@ -resource_attributes=deployment.environment=test -java_agent_jar=/usr/lib/splunk-instrumentation/splunk-otel-javaagent.jar diff --git a/instrumentation/testdata/instrumentation-options.conf b/instrumentation/testdata/instrumentation-options.conf deleted file mode 100644 index aa74a6262b..0000000000 --- a/instrumentation/testdata/instrumentation-options.conf +++ /dev/null @@ -1,8 +0,0 @@ -java_agent_jar=/usr/lib/splunk-instrumentation/splunk-otel-javaagent.jar -service_name=default.service -resource_attributes=deployment.environment=test -disable_telemetry=true -generate_service_name=true -enable_profiler=true -enable_profiler_memory=true -enable_metrics=true diff --git a/instrumentation/tests/java/Dockerfile b/instrumentation/tests/java/Dockerfile new file mode 100644 index 0000000000..3f66808ffa --- /dev/null +++ b/instrumentation/tests/java/Dockerfile @@ -0,0 +1,22 @@ +ARG BASE=busybox +FROM $BASE + +COPY Main.java . + +RUN javac Main.java && \ + jar cfe Main.jar Main Main.class + +RUN mkdir -p /etc/splunk/ + +COPY zeroconfig.conf /etc/splunk/zeroconfig_java.conf + +CMD java -jar Main.jar + +ENV OTEL_SERVICE_NAME iknowmyownservicename + +ENV ANOTHER_VAR foo + +COPY libsplunk.so /usr/lib/splunk-instrumentation/libsplunk.so + +RUN echo /usr/lib/splunk-instrumentation/libsplunk.so >> /etc/ld.so.preload + diff --git a/instrumentation/tests/java/Main.java b/instrumentation/tests/java/Main.java new file mode 100644 index 0000000000..68f01d2139 --- /dev/null +++ b/instrumentation/tests/java/Main.java @@ -0,0 +1,10 @@ +import java.util.Map; + +public class Main { + public static void main(String[] args) { + Map env = System.getenv(); + for (String envName : env.keySet()) { + System.out.format("%s=%s%n", envName, env.get(envName)); + } + } +} \ No newline at end of file diff --git a/instrumentation/tests/java/Makefile b/instrumentation/tests/java/Makefile new file mode 100644 index 0000000000..e69de29bb2 diff --git a/instrumentation/tests/java/test.sh b/instrumentation/tests/java/test.sh new file mode 100755 index 0000000000..cef1766f1b --- /dev/null +++ b/instrumentation/tests/java/test.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +set -euo pipefail + +arch="${ARCH:-amd64}" +BASE="eclipse-temurin:11" +if [[ arch = "arm64" ]]; then + BASE="arm64v8/eclipse-temurin:11" +fi + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + +cp "${SCRIPT_DIR}/../../dist/libsplunk_${arch}.so" libsplunk.so +docker buildx build -q --platform linux/${arch} --build-arg BASE=$BASE -o type=image,name=zeroconfig-test-java,push=false . +OUTPUT=$(docker run --rm zeroconfig-test-java) +echo "========== OUTPUT ==========" +echo "$OUTPUT" +echo "============================" +echo "Test presence of OTEL_RESOURCE_ATTRIBUTES" +echo "$OUTPUT" | grep "OTEL_RESOURCE_ATTRIBUTES=foo=bar,this=that" > /dev/null && echo "Test passes" || exit 1 +echo "Test presence of OTEL_SERVICE_NAME" +echo "$OUTPUT" | grep "OTEL_SERVICE_NAME=iknowmyownservicename" > /dev/null && echo "Test passes" || exit 1 +echo "Test presence of SPLUNK_METRICS_ENABLED" +echo "$OUTPUT" | grep "SPLUNK_METRICS_ENABLED=abcd" > /dev/null && echo "Test passes" || exit 1 +echo "Test presence of ANOTHER_VAR" +echo "$OUTPUT" | grep "ANOTHER_VAR=foo" > /dev/null && echo "Test passes" || exit 1 +echo "Test absence of FOO" +echo "$OUTPUT" | grep -v "FOO" > /dev/null && echo "Test passes" || exit 1 +echo "Test absence of OTEL_EXPORTER_OTLP_ENDPOINT" +echo "$OUTPUT" | grep -v "OTEL_EXPORTER_OTLP_ENDPOINT" > /dev/null && echo "Test passes" || exit 1 + +# Check we didn't inject env vars into processes outside of java. +OUTPUT_BASH=$(docker run --rm zeroconfig-test-java /usr/bin/env) +echo "======= BASH OUTPUT ========" +echo "$OUTPUT_BASH" +echo "============================" +echo "$OUTPUT_BASH" | grep -v "OTEL_RESOURCE_ATTRIBUTES" | grep -v "OTEL_SERVICE_NAME" | grep -v "SPLUNK_METRICS_ENABLED" > /dev/null && echo "Test passes" || exit 1 diff --git a/instrumentation/tests/java/zeroconfig.conf b/instrumentation/tests/java/zeroconfig.conf new file mode 100644 index 0000000000..e78ea9a59e --- /dev/null +++ b/instrumentation/tests/java/zeroconfig.conf @@ -0,0 +1,19 @@ +# Environment variables we want to inject +FOO=bar +OTEL_RESOURCE_ATTRIBUTES=foo=bar,this=that +OTEL_SERVICE_NAME=myservice +# Empty lines: + + +# Invalid content +invalid + +# Key contains a space character: +OTEL_SERVICE_NAME OTEL_EXPORTER_OTLP_ENDPOINT=thisisinvalid + +# Content exactly at 1023 characters +SPLUNK_METRICS_ENABLED=abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabc +# Content past limit of 1024 characters +SPLUNK_PROFILER_MEMORY_ENABLED=abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvjklmnopqOTEL_EXPORTER_OTLP_ENDPOINT=qrstuvwxyzabcdefghijklmnopqrstuvwxyz +# This value is after the value past 1024 characters and will not be read: +OTEL_EXPORTER_OTLP_ENDPOINT=127.0.0.1:4567 \ No newline at end of file diff --git a/instrumentation/tests/nodejs/Dockerfile b/instrumentation/tests/nodejs/Dockerfile new file mode 100644 index 0000000000..6554805c82 --- /dev/null +++ b/instrumentation/tests/nodejs/Dockerfile @@ -0,0 +1,14 @@ +ARG BASE=busybox +FROM $BASE + +COPY index.js . + +RUN mkdir -p /etc/splunk/ + +COPY zeroconfig.conf /etc/splunk/zeroconfig_node.conf + +CMD node index.js + +COPY libsplunk.so /usr/lib/splunk-instrumentation/libsplunk.so + +RUN echo /usr/lib/splunk-instrumentation/libsplunk.so >> /etc/ld.so.preload \ No newline at end of file diff --git a/instrumentation/tests/nodejs/index.js b/instrumentation/tests/nodejs/index.js new file mode 100644 index 0000000000..9d2bf4f0cb --- /dev/null +++ b/instrumentation/tests/nodejs/index.js @@ -0,0 +1,3 @@ +Object.keys(process.env).forEach(function(key) { + console.log(key + '=' + process.env[key]); +}); \ No newline at end of file diff --git a/instrumentation/tests/nodejs/test.sh b/instrumentation/tests/nodejs/test.sh new file mode 100755 index 0000000000..5233233146 --- /dev/null +++ b/instrumentation/tests/nodejs/test.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +set -euo pipefail + +arch="${ARCH:-amd64}" +BASE="node:16" +if [[ arch = "arm64" ]]; then + BASE="arm64v8/node:16" +fi +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + +cp "${SCRIPT_DIR}/../../dist/libsplunk_${arch}.so" libsplunk.so +docker buildx build -q --platform linux/${arch} --build-arg BASE=$BASE -o type=image,name=zeroconfig-test-nodejs,push=false . +OUTPUT=$(docker run --rm zeroconfig-test-nodejs) +echo "========== OUTPUT ==========" +echo "$OUTPUT" +echo "============================" +echo "Test presence of OTEL_RESOURCE_ATTRIBUTES" +echo $OUTPUT | grep "OTEL_RESOURCE_ATTRIBUTES=foo=bar,this=that" > /dev/null && echo "Test passes" || exit 1 +echo "Test presence of OTEL_SERVICE_NAME" +echo $OUTPUT | grep "OTEL_SERVICE_NAME=myservice" > /dev/null && echo "Test passes" || exit 1 +echo "Test presence of SPLUNK_METRICS_ENABLED" +echo $OUTPUT | grep "SPLUNK_METRICS_ENABLED=abcd" > /dev/null && echo "Test passes" || exit 1 +echo "Test absence of FOO" +echo $OUTPUT | grep -v "FOO" > /dev/null && echo "Test passes" || exit 1 +echo "Test absence of OTEL_EXPORTER_OTLP_ENDPOINT" +echo $OUTPUT | grep -v "OTEL_EXPORTER_OTLP_ENDPOINT" > /dev/null && echo "Test passes" || exit 1 diff --git a/instrumentation/tests/nodejs/zeroconfig.conf b/instrumentation/tests/nodejs/zeroconfig.conf new file mode 100644 index 0000000000..ca43ad487c --- /dev/null +++ b/instrumentation/tests/nodejs/zeroconfig.conf @@ -0,0 +1,16 @@ +# Environment variables we want to inject +FOO=bar +OTEL_RESOURCE_ATTRIBUTES=foo=bar,this=that +OTEL_SERVICE_NAME=myservice +# Empty lines: + + +# Invalid content +invalid + +# Content exactly at 1023 characters +SPLUNK_METRICS_ENABLED=abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabc +# Content past limit of 1024 characters +SPLUNK_PROFILER_MEMORY_ENABLED=abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvjklmnopqOTEL_EXPORTER_OTLP_ENDPOINT=qrstuvwxyzabcdefghijklmnopqrstuvwxyz +# This value is after the value past 1024 characters and will not be read: +OTEL_EXPORTER_OTLP_ENDPOINT=127.0.0.1:4567 \ No newline at end of file