Skip to content

Commit

Permalink
zc: read jar file path and service name from a config file (open-tele…
Browse files Browse the repository at this point in the history
…metry#1255)

* Read jar file path and service name from a config file
* zc: rename config example file
  • Loading branch information
pmcollins authored Feb 25, 2022
1 parent 9cd4e52 commit 911d125
Show file tree
Hide file tree
Showing 12 changed files with 296 additions and 70 deletions.
1 change: 1 addition & 0 deletions instrumentation/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ RUN apt-get update && \
WORKDIR /libsplunk

COPY src /libsplunk/src
COPY testdata/splunk.conf /libsplunk/testdata/splunk.conf
COPY Makefile /libsplunk/Makefile
15 changes: 9 additions & 6 deletions instrumentation/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,20 @@ obj:
clean:
rm -f tests so/* obj/*

obj/logger.o: obj src/logger.c
obj/logger.o: obj src/logger.c src/logger.h
gcc -c -Wall -Werror -fpic -o obj/logger.o src/logger.c

obj/splunk.o: obj src/splunk.c
obj/config.o: obj src/config.c src/config.h
gcc -c -Wall -Werror -fpic -o obj/config.o src/config.c

obj/splunk.o: obj src/splunk.c src/splunk.h
gcc -c -Wall -Werror -fpic -o obj/splunk.o src/splunk.c

so/libsplunk.so: obj so obj/splunk.o obj/logger.o
gcc -shared -o so/libsplunk.so obj/splunk.o obj/logger.o
so/libsplunk.so: obj so obj/splunk.o obj/logger.o obj/config.o
gcc -shared -o so/libsplunk.so obj/splunk.o obj/logger.o obj/config.o

tests: src/splunk.c src/test_main.c
gcc -o tests src/test_main.c src/logger_test.c src/splunk.c
tests: src/test_main.h src/test_main.c src/logger.h src/logger_test.c obj/config.o obj/splunk.o
gcc -o tests src/test_main.c src/logger_test.c obj/config.o obj/splunk.o

.PHONY: test
test: tests
Expand Down
79 changes: 79 additions & 0 deletions instrumentation/src/config.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#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 load_config(logger log, struct config *cfg, char *file_name) {
read_config_file(log, cfg, file_name);
char log_line[MAX_LOG_LINE_LEN];
if (cfg->service_name == NULL) {
strcpy(log_line, "service_name not found in config, using default: ");
strncat(log_line, default_service_name, MAX_LOG_LINE_LEN - strlen(log_line) - 1);
log_debug(log, log_line);
cfg->service_name = strdup(default_service_name);
}
if (cfg->java_agent_jar == NULL) {
strcpy(log_line, "java_agent_jar not found in config, using default: ");
strncat(log_line, default_jar_path, MAX_LOG_LINE_LEN - strlen(log_line) - 1);
log_debug(log, log_line);
cfg->java_agent_jar = strdup(default_jar_path);
}
}

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);
}
}
}

void split_on_eq(char *string, struct kv *pair) {
pair->k = strsep(&string, "=");
pair->v = string;
}

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);
}
}
17 changes: 17 additions & 0 deletions instrumentation/src/config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#ifndef INSTRUMENTATION_CONFIG_H
#define INSTRUMENTATION_CONFIG_H

#include <stdbool.h>

#include "logger.h"

struct config {
char *java_agent_jar;
char *service_name;
};

void load_config(logger log, struct config *cfg, char *file_name);

void free_config(struct config *cfg);

#endif //INSTRUMENTATION_CONFIG_H
4 changes: 4 additions & 0 deletions instrumentation/src/logger.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ 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);
}
6 changes: 4 additions & 2 deletions instrumentation/src/logger.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#ifndef SPLUNK_INSTRUMENTATION_LOGGER_H
#define SPLUNK_INSTRUMENTATION_LOGGER_H

#define TEST_LOGS_MAX_LEN 256
#define MAX_LOG_LINE_LEN 1024

typedef struct logger_impl *logger;

Expand All @@ -11,7 +11,9 @@ void log_debug(logger l, char *s);

void log_info(logger l, char *s);

int get_logs(logger l, char *buf[256]);
void log_warning(logger l, char *s);

int get_logs(logger l, char **buf);

void free_logger(logger l);

Expand Down
18 changes: 15 additions & 3 deletions instrumentation/src/logger_test.c
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#include <stdlib.h>
#include <string.h>
#include "logger.h"

struct logger_impl {
int i;
char *logs[TEST_LOGS_MAX_LEN];
char *logs[MAX_LOG_LINE_LEN];
};

logger new_logger() {
Expand All @@ -14,15 +15,26 @@ logger new_logger() {
return ref;
}

void save_log(logger l, char *s) {
l->logs[l->i++] = strdup(s);
}

void log_info(logger l, char *s) {
l->logs[l->i++] = s;
save_log(l, s);
}

void log_debug(logger l, char *s) {
l->logs[l->i++] = 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);
}

Expand Down
81 changes: 65 additions & 16 deletions instrumentation/src/splunk.c
Original file line number Diff line number Diff line change
@@ -1,55 +1,104 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>

#include "config.h"
#include "splunk.h"

#define FLAG_LEN 256
#define ENV_VAR_LEN 512
#define MAX_SERVICE_NAME_LEN 256
#define MAX_JAR_PATH_LEN 256

#define FLAG_PREFIX "-javaagent:";
#define JAVA_TOOL_OPTIONS_PREFIX "-javaagent:";
#define OTEL_RESOURCE_ATTRIBUTES_PREFIX "service.name="

extern char *program_invocation_short_name;
char *const AGENT_JAR_PATH = "/usr/lib/splunk-instrumentation/splunk-otel-javaagent.jar";

bool has_read_access(const char *s);

void set_java_tool_options(logger log, struct config *cfg);

void set_service_name(logger log, struct config *cfg);

bool is_disable_env_set();

// The entry point for all executables prior to their execution. If the executable is named "java", we
// set JAVA_TOOL_OPTIONS to the path of the java agent jar.
void __attribute__((constructor)) splunk_instrumentation_enter() {
logger l = new_logger();
auto_instrument(l, has_read_access, program_invocation_short_name, AGENT_JAR_PATH);
auto_instrument(l, has_read_access, program_invocation_short_name, load_config);
free_logger(l);
}

void auto_instrument(logger log, has_access_t has_access, const char *program_name, const char *jar_path) {
if (strcmp(program_name, "java") != 0) {
void auto_instrument(logger log, has_access_func_t has_access, const char *program_name, load_config_func_t load_config_func) {
if (!streq(program_name, "java")) {
return;
}
if (is_disable_env_set()) {
log_debug(log, "disable_env_set, quitting");
return;
}
if (!has_access(jar_path)) {

struct config cfg = {.java_agent_jar = NULL, .service_name = NULL};
load_config_func(log, &cfg, conf_file);

if (!has_access(cfg.java_agent_jar)) {
log_info(log, "agent jar not found or no read access, quitting");
return;
}
char opts[FLAG_LEN] = FLAG_PREFIX;
if (strlen(opts) + strlen(jar_path) > FLAG_LEN) {
log_info(log, "jar path too long");

set_java_tool_options(log, &cfg);
set_service_name(log, &cfg);

free_config(&cfg);
}

void set_service_name(logger log, struct config *cfg) {
char otel_resource_attributes[ENV_VAR_LEN] = OTEL_RESOURCE_ATTRIBUTES_PREFIX;
char log_line[MAX_LOG_LINE_LEN];
size_t service_name_len = strlen(((*cfg).service_name));
if (service_name_len > MAX_SERVICE_NAME_LEN) {
sprintf(log_line, "service_name too long: got %zu chars, max %d chars", service_name_len, MAX_SERVICE_NAME_LEN);
log_warning(log, log_line);
return;
}
strncat(opts, jar_path, FLAG_LEN);
log_debug(log, "setting JAVA_TOOL_OPTIONS");
setenv("JAVA_TOOL_OPTIONS", opts, 0);
strcat(otel_resource_attributes, (*cfg).service_name);
sprintf(log_line, "setting OTEL_RESOURCE_ATTRIBUTES='%s'", otel_resource_attributes);
log_debug(log, log_line);
setenv("OTEL_RESOURCE_ATTRIBUTES", otel_resource_attributes, 0);
}

bool streq(char *a, char *b) {
return strcmp(a, b) == 0;
void set_java_tool_options(logger log, struct config *cfg) {
char java_tool_options[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_JAR_PATH_LEN) {
sprintf(log_line, "jar_path too long: got %zu chars, max %d chars", jar_path_len, MAX_JAR_PATH_LEN);
log_warning(log, log_line);
return;
}
strcat(java_tool_options, (*cfg).java_agent_jar);
sprintf(log_line, "setting JAVA_TOOL_OPTIONS='%s'", java_tool_options);
log_debug(log, log_line);
setenv("JAVA_TOOL_OPTIONS", java_tool_options, 0);
}

bool is_disable_env_set() {
char *env = getenv(DISABLE_ENV_VAR_NAME);
char *env = getenv(disable_env_var_name);
return env && !streq("false", env) && !streq("FALSE", env) && !streq("0", env);
}

bool has_read_access(const char *s) {
return access(s, R_OK) == 0;
}

bool streq(const char *expected, const char *actual) {
if (expected == NULL && actual == NULL) {
return true;
}
if (expected == NULL || actual == NULL) {
return false;
}
return strcmp(expected, actual) == 0;
}
17 changes: 12 additions & 5 deletions instrumentation/src/splunk.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,22 @@

#include <stdbool.h>
#include "logger.h"
#include "config.h"

static char *const DISABLE_ENV_VAR_NAME = "DISABLE_SPLUNK_AUTOINSTRUMENTATION";
static char *const conf_file = "/usr/lib/splunk-instrumentation/splunk.conf";

typedef bool (*has_access_t)(const char *);
static char *const default_jar_path = "/usr/lib/splunk-instrumentation/splunk-otel-javaagent.jar";

void auto_instrument(logger log, has_access_t has_access, const char *program_name, const char *jar_path);
static char *const default_service_name = "default.service";

bool has_read_access(const char *s);
static char *const disable_env_var_name = "DISABLE_SPLUNK_AUTOINSTRUMENTATION";

bool is_disable_env_set();
typedef bool (*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);

bool streq(const char *expected, const char *actual);

#endif //SPLUNK_INSTRUMENTATION_SPLUNK_H
Loading

0 comments on commit 911d125

Please sign in to comment.