diff --git a/.github/workflows/auto-instrumentation.yml b/.github/workflows/auto-instrumentation.yml index 80408b1d1a..c7704f1226 100644 --- a/.github/workflows/auto-instrumentation.yml +++ b/.github/workflows/auto-instrumentation.yml @@ -8,43 +8,51 @@ on: paths: - '.github/workflows/auto-instrumentation.yml' - 'instrumentation/**' + - 'internal/buildscripts/packaging/tests/helpers/**' + - 'internal/buildscripts/packaging/tests/instrumentation/**' + - 'internal/buildscripts/packaging/tests/requirements.txt' + - '!**.md' concurrency: group: auto-instrumentation-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true +env: + PYTHON_VERSION: '3.11' + PIP_VERSION: '22.0.4' + REQUIREMENTS_PATH: "internal/buildscripts/packaging/tests/requirements.txt" + GO_VERSION: 1.20.10 + jobs: - libsplunk: + cross-compile: # Use 20.04.5 until https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/16450 is resolved runs-on: ubuntu-20.04 strategy: matrix: - ARCH: [ "amd64", "arm64" ] + SYS_BINARIES: [ "binaries-linux_amd64", "binaries-linux_arm64" ] steps: - name: Check out the codebase. uses: actions/checkout@v4 - - name: Set up QEMU - if: ${{ matrix.ARCH == 'arm64' }} - uses: docker/setup-qemu-action@v3 + - name: Set up Go + uses: actions/setup-go@v4 with: - platforms: arm64 - image: tonistiigi/binfmt:qemu-v7.0.0 + go-version: ${{ env.GO_VERSION }} + cache-dependency-path: '**/go.sum' - - name: Build libsplunk.so - run: make -C instrumentation dist ARCH=${{ matrix.ARCH }} + - name: Build Collector + run: | + make ${{ matrix.SYS_BINARIES }} - name: Upload artifact uses: actions/upload-artifact@v3 with: - name: libsplunk-${{ matrix.ARCH }} - path: ./instrumentation/dist/libsplunk_${{ matrix.ARCH }}.so + name: ${{ matrix.SYS_BINARIES }} + path: | + ./bin/* build-package: - name: build-package - # Use 20.04.5 until https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/16450 is resolved runs-on: ubuntu-20.04 - needs: [libsplunk] strategy: matrix: SYS_PACKAGE: [ "deb", "rpm" ] @@ -55,86 +63,124 @@ jobs: with: fetch-depth: 0 - - name: Downloading libsplunk-${{ matrix.ARCH }} - uses: actions/download-artifact@v3 + - uses: docker/setup-qemu-action@v2 + if: ${{ matrix.ARCH != 'amd64' }} with: - name: libsplunk-${{ matrix.ARCH }} - path: ./instrumentation/dist + platforms: ${{ matrix.ARCH }} + image: tonistiigi/binfmt:qemu-v7.0.0 - - name: Build ${{ matrix.SYS_PACKAGE }} ${{ matrix.ARCH }} package - run: | - gitRef=(${GITHUB_REF//// }) - if [[ "${gitRef[1]}" = "tags" ]] ; - then - echo "TAG_NAME=${gitRef[2]}" >> $GITHUB_ENV - else - echo "TAG_NAME=" >> $GITHUB_ENV - fi - make -C instrumentation ${{ matrix.SYS_PACKAGE }}-package SKIP_COMPILE=true VERSION="${TAG_NAME:-}" ARCH="${{ matrix.ARCH }}" + - name: Run tests + run: make -C instrumentation tests ARCH=${{ matrix.ARCH }} + + - name: Build ${{ matrix.ARCH }} ${{ matrix.SYS_PACKAGE }} package + run: make -C instrumentation/ ${{ matrix.SYS_PACKAGE }}-package ARCH="${{ matrix.ARCH }}" - name: Upload artifact uses: actions/upload-artifact@v3 with: name: splunk-otel-auto-instrumentation-${{ matrix.ARCH }}-${{ matrix.SYS_PACKAGE }} - path: ./instrumentation/dist/splunk-otel-auto-instrumentation*.${{ matrix.SYS_PACKAGE }} + path: ./instrumentation/dist/*.${{ matrix.SYS_PACKAGE }} - test-deb-package: - name: test-deb-package - # Use 20.04.5 until https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/16450 is resolved + test-package-matrix: runs-on: ubuntu-20.04 - needs: [build-package] - strategy: - matrix: - DISTRO: [ "debian:8", "debian:9", "debian:10", "ubuntu:16.04", "ubuntu:18.04", "ubuntu:20.04" ] - ARCH: [ "amd64", "arm64" ] - exclude: - - DISTRO: debian:8 - ARCH: arm64 steps: - - name: Check out the codebase. + - name: Check out code uses: actions/checkout@v4 - - name: Downloading splunk-otel-auto-instrumentation-${{ matrix.ARCH }}-deb - uses: actions/download-artifact@v3 - with: - name: splunk-otel-auto-instrumentation-${{ matrix.ARCH }}-deb - path: ./instrumentation/dist - - - name: Set up QEMU - if: ${{ matrix.ARCH == 'arm64' }} - uses: docker/setup-qemu-action@v3 - with: - platforms: arm64 - image: tonistiigi/binfmt:qemu-v7.0.0 - - - name: Test - run: docker run --platform linux/${{ matrix.ARCH }} --rm -v $(pwd):/repo -w /repo ${{ matrix.DISTRO }} /repo/instrumentation/packaging/fpm/test.sh deb ${{ matrix.ARCH }} - - test-rpm-package: - name: test-rpm-package + - name: Get matrix + id: get-matrix + run: | + # create test matrix for distro and arch + dockerfiles=$(find internal/buildscripts/packaging/tests/instrumentation/images/ -name "Dockerfile.*" | cut -d '.' -f2- | sort -u) + if [ -z "$dockerfiles" ]; then + echo "Failed to get dockerfiles from internal/buildscripts/packaging/tests/instrumentation/images!" >&2 + exit 1 + fi + distro=$(for d in $dockerfiles; do echo -n "\"$d\","; done) + arch="\"amd64\", \"arm64\"" + matrix="{\"DISTRO\": [${distro%,}], \"ARCH\": [${arch}]}" + echo "$matrix" | jq + echo "matrix=${matrix}" >> $GITHUB_OUTPUT + outputs: + matrix: ${{ steps.get-matrix.outputs.matrix }} + + test-package: # Use 20.04.5 until https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/16450 is resolved - runs-on: ubuntu-20.04 - needs: [build-package] + runs-on: ${{ fromJSON('["ubuntu-20.04", "ubuntu-22.04"]')[matrix.DISTRO == 'amazonlinux-2023'] }} + timeout-minutes: 60 + needs: [cross-compile, build-package, test-package-matrix] strategy: - matrix: - DISTRO: [ "centos:7", "centos:8", "amazonlinux:2", "opensuse/leap:42", "opensuse/leap:15", "oraclelinux:7", "oraclelinux:8" ] - ARCH: [ "amd64", "arm64" ] + matrix: ${{ fromJSON(needs.test-package-matrix.outputs.matrix) }} + fail-fast: false steps: - name: Check out the codebase. uses: actions/checkout@v4 - - name: Downloading splunk-otel-auto-instrumentation-${{ matrix.ARCH }}-rpm - uses: actions/download-artifact@v3 + - name: Get package type for ${{ matrix.DISTRO }} + run: | + for pkg in "deb" "rpm"; do + if [[ -f "internal/buildscripts/packaging/tests/instrumentation/images/${pkg}/Dockerfile.${{ matrix.DISTRO }}" ]]; then + echo "SYS_PACKAGE=${pkg}" >> $GITHUB_ENV + exit 0 + fi + done + echo "Unknown distro '${{ matrix.DISTRO }}'!" + exit 1 + + - uses: actions/download-artifact@v3 + with: + name: binaries-linux_${{ matrix.ARCH }} + path: ./bin + + - uses: actions/download-artifact@v3 with: - name: splunk-otel-auto-instrumentation-${{ matrix.ARCH }}-rpm + name: splunk-otel-auto-instrumentation-${{ matrix.ARCH }}-${{ env.SYS_PACKAGE }} path: ./instrumentation/dist - - name: Set up QEMU - if: ${{ matrix.ARCH == 'arm64'}} - uses: docker/setup-qemu-action@v3 + - uses: docker/setup-qemu-action@v3 + if: ${{ matrix.ARCH != 'amd64' }} with: - platforms: arm64 + platforms: ${{ matrix.ARCH }} image: tonistiigi/binfmt:qemu-v7.0.0 - - name: Test - run: docker run --platform linux/${{ matrix.ARCH }} --rm -v $(pwd):/repo -w /repo ${{ matrix.DISTRO }} /repo/instrumentation/packaging/fpm/test.sh rpm ${{ matrix.ARCH }} + - name: Setup python + uses: actions/setup-python@v4 + with: + python-version: ${{ env.PYTHON_VERSION }} + cache: 'pip' + cache-dependency-path: ${{ env.REQUIREMENTS_PATH }} + + - name: Install pytest + run: | + if which pip; then + pip install --upgrade 'pip==${{ env.PIP_VERSION }}' + else + curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py + python get-pip.py 'pip==${{ env.PIP_VERSION }}' + fi + pip install -r "${{ env.REQUIREMENTS_PATH }}" + + - name: Test ${{ env.SYS_PACKAGE }} on ${{ matrix.DISTRO }} ${{ matrix.ARCH }} + id: pytest + continue-on-error: true + run: | + distro="${{ matrix.DISTRO }}" + if [[ "$distro" = "amazonlinux-2" ]]; then + # workaround for pytest substring matching + distro="amazonlinux-2 and not amazonlinux-2023" + fi + python3 -u -m pytest -s --verbose -k "$distro and ${{ matrix.ARCH }}" \ + internal/buildscripts/packaging/tests/instrumentation/instrumentation_test.py + + # qemu, networking, running systemd in containers, etc., can be flaky + - name: Re-run failed tests + if: ${{ steps.pytest.outcome == 'failure' }} + run: | + distro="${{ matrix.DISTRO }}" + if [[ "$distro" = "amazonlinux-2" ]]; then + # workaround for pytest substring matching + distro="amazonlinux-2 and not amazonlinux-2023" + fi + python3 -u -m pytest -s --verbose -k "$distro and ${{ matrix.ARCH }}" \ + --last-failed \ + internal/buildscripts/packaging/tests/instrumentation/instrumentation_test.py 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/.gitlab-ci.yml b/.gitlab-ci.yml index 35f60106e1..edb0037b4e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -157,6 +157,16 @@ update-javaagent: - .gitlab/install-gh-cli.sh - .gitlab/update-javaagent.sh +update-nodejs-agent: + only: + - schedules + stage: update-deps + needs: [] + dependencies: [] + script: + - .gitlab/install-gh-cli.sh + - .gitlab/update-nodejs-agent.sh + tidy-dependabot-pr: rules: - if: $CI_COMMIT_BRANCH =~ /^dependabot\/go_modules\/.*/ && $CI_COMMIT_AUTHOR =~ /^dependabot.*/ diff --git a/.gitlab/update-nodejs-agent.sh b/.gitlab/update-nodejs-agent.sh new file mode 100755 index 0000000000..4d44fbbc2e --- /dev/null +++ b/.gitlab/update-nodejs-agent.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash +set -euo pipefail + +# NOTE: this script is meant to be run on the GitLab CI, it depends on GitLab CI variables +# Based on https://github.com/signalfx/splunk-otel-java/blob/c9134906c84e9a32a974dec4b380453fe1757410/scripts/propagate-version.sh + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +# shellcheck source-path=SCRIPTDIR +source "${SCRIPT_DIR}/common.sh" + +ROOT_DIR="${SCRIPT_DIR}/../" +cd "${ROOT_DIR}" + +create_collector_pr() { + local repo="signalfx/splunk-otel-collector" + local repo_url="https://srv-gh-o11y-gdi:${GITHUB_TOKEN}@github.com/${repo}.git" + local branch="create-pull-request/update-nodejs-agent" + local message="Update splunk-otel-js to latest" + + echo ">>> Cloning the $repo repository ..." + git clone "$repo_url" collector-mirror + cd collector-mirror + + setup_branch "$branch" "$repo_url" + + echo ">>> Getting latest splunk-otel-js release ..." + tag="$( gh release view --repo "https://github.com/signalfx/splunk-otel-js" --json tagName --jq 'select(.isDraft|not and .isPrelease|not) | .tagName' )" + if [[ -n "$tag" ]]; then + echo ">>> Updating splunk-otel-js version to $tag ..." + echo "$tag" > instrumentation/packaging/nodejs-agent-release.txt + else + echo "ERROR: Failed to get latest release tag from https://github.com/signalfx/splunk-otel-js !" >&2 + exit 1 + fi + + # Only create the PR if there are changes + if ! git diff --exit-code >/dev/null 2>&1; then + git commit -S -am "$message" + git push -f "$repo_url" "$branch" + echo ">>> Creating the PR ..." + gh pr create \ + --draft \ + --repo "$repo" \ + --title "$message" \ + --body "$message" \ + --base main \ + --head "$branch" + fi +} + +setup_gpg +import_gpg_secret_key "$GITHUB_BOT_GPG_KEY" +setup_git +create_collector_pr diff --git a/CHANGELOG.md b/CHANGELOG.md index cce281bc35..05d24bab1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,10 +2,30 @@ ## Unreleased +### 🛑 Breaking changes 🛑 + +- (Splunk) Auto Instrumentation for Linux (manual installation/upgrade) ([#3791](https://github.com/signalfx/splunk-otel-collector/pull/3791)): + - The `/usr/lib/splunk-instrumentation/instrumentation.conf` config file is no longer + supported, and is replaced by `/etc/splunk/zeroconfig/java.conf`. If the `splunk-otel-auto-instrumentation` deb/rpm + package is manually upgraded, the options within `/usr/lib/splunk-instrumentation/instrumentation.conf` will need to + be manually migrated to their corresponding environment variables within `/etc/splunk/zeroconfig/java.conf`. + - Manual installation of the `splunk-otel-auto-instrumentation` deb/rpm package no longer automatically adds + `/usr/lib/splunk-instrumentation/libsplunk.so` to `/etc/ld.so.preload`. + - Manual upgrade of the `splunk-otel-auto-instrumentation` deb/rpm package will automatically remove + `/usr/lib/splunk-instrumentation/libsplunk.so` from `/etc/ld.so.preload`. + - The `splunk.linux-autoinstr.executions` metric is no longer generated by `libsplunk.so`. + - See [Splunk OpenTelemetry Zero Configuration Auto Instrumentation for Linux](https://github.com/signalfx/splunk-otel-collector/blob/main/instrumentation/README.md) + for manual installation/configuration details. + ### 💡 Enhancements 💡 - (Splunk) Update golang to 1.20.10 ([#3770](https://github.com/signalfx/splunk-otel-collector/pull/3770)) - (Splunk) Add debian 12 support to installer ([#3766](https://github.com/signalfx/splunk-otel-collector/pull/3766)) +- (Splunk) Add new Auto Instrumentation options for the Linux installer script ([#3791](https://github.com/signalfx/splunk-otel-collector/pull/3791)): + - `--with[out]-systemd-instrumentation`: Activate auto instrumentation for only `systemd` services without preloading + the `libsplunk.so` shared object library (default: `--without-systemd-instrumentation`) + - `--otlp-endpoint host:port`: Set the OTLP gRPC endpoint for captured traces (default: `http://LISTEN_INTERFACE:4317` + where `LISTEN_INTERFACE` is the value from the `--listen-interface` option if specified, or `127.0.0.1` otherwise) ## v0.86.0 diff --git a/docs/getting-started/linux-installer.md b/docs/getting-started/linux-installer.md index fabd3e0609..57a8f33790 100644 --- a/docs/getting-started/linux-installer.md +++ b/docs/getting-started/linux-installer.md @@ -285,21 +285,40 @@ applicable for `td-agent` versions 4.1 or newer): ### Auto Instrumentation ->To see all supported options and defaults **before** installation, run: ->```sh ->curl -sSL https://dl.signalfx.com/splunk-otel-collector.sh > /tmp/splunk-otel-collector.sh && \ ->sh /tmp/splunk-otel-collector.sh -h ->``` +[Splunk OpenTelemetry Auto Instrumentation](../../instrumentation/README.md) +installs and supports configuration of the following Auto Instrumentation +agent(s): + +- [Java](https://docs.splunk.com/Observability/gdi/get-data-in/application/java/get-started.html) + +> To see all supported options and defaults **before** installation, run: +> ```sh +> curl -sSL https://dl.signalfx.com/splunk-otel-collector.sh > /tmp/splunk-otel-collector.sh && \ +> sh /tmp/splunk-otel-collector.sh -h +> ``` #### Installation -To install the Collector and the Splunk OpenTelemetry Auto Instrumentation for -Java packages, run the installer script with the `--with-instrumentation` -option: -```sh -curl -sSL https://dl.signalfx.com/splunk-otel-collector.sh > /tmp/splunk-otel-collector.sh && \ -sudo sh /tmp/splunk-otel-collector.sh --with-instrumentation --realm SPLUNK_REALM -- SPLUNK_ACCESS_TOKEN -``` +To install the Collector and the [Splunk OpenTelemetry Auto Instrumentation]( +../../instrumentation/README.md) packages, run the installer script with either +of the following options: + +- `--with-instrumentation`: Install and activate the provided Auto + Instrumentation agent(s) for ***all*** supported processes by automatically + adding the [`libsplunk.so`](../../instrumentation/libsplunk.md) shared object + library to `/etc/ld.so.preload`: + ```sh + curl -sSL https://dl.signalfx.com/splunk-otel-collector.sh > /tmp/splunk-otel-collector.sh && \ + sudo sh /tmp/splunk-otel-collector.sh --with-instrumentation --realm SPLUNK_REALM -- SPLUNK_ACCESS_TOKEN + ``` + +- `--with-systemd-instrumentation`: Install and activate the provided Auto + Instrumentation agent(s) for ***all*** supported `systemd` services by + installing a [`systemd` drop-in file](../../instrumentation/systemd.md): + ```sh + curl -sSL https://dl.signalfx.com/splunk-otel-collector.sh > /tmp/splunk-otel-collector.sh && \ + sudo sh /tmp/splunk-otel-collector.sh --with-systemd-instrumentation --realm SPLUNK_REALM -- SPLUNK_ACCESS_TOKEN + ``` To automatically define the optional `deployment.environment` resource attribute at installation time, run the installer script with the @@ -307,35 +326,46 @@ attribute at installation time, run the installer script with the attribute value, for example, `prod`): ```sh curl -sSL https://dl.signalfx.com/splunk-otel-collector.sh > /tmp/splunk-otel-collector.sh && \ -sudo sh /tmp/splunk-otel-collector.sh --with-instrumentation --deployment-environment VALUE --realm SPLUNK_REALM -- SPLUNK_ACCESS_TOKEN +sudo sh /tmp/splunk-otel-collector.sh --with-[systemd]-instrumentation --deployment-environment VALUE --realm SPLUNK_REALM -- SPLUNK_ACCESS_TOKEN ``` -**Note:** After successful installation, the Java application(s) on the host -need to be manually started/restarted for automatic instrumentation to take -effect. +**Note:** After successful installation, reboot the host or manually +start/restart the Java application(s) on the host for Auto Instrumentation to +take effect. #### Post-Install Configuration -- The `/etc/ld.so.preload` file will be automatically created/updated with the - default path to the installed instrumentation library - (`/usr/lib/splunk-instrumentation/libsplunk.so`). If necessary, custom - library paths can be manually added to this file. -- The `/usr/lib/splunk-instrumentation/instrumentation.conf` configuration file - can be manually configured for resource attributes and other parameters. By - default, this file will contain the `java_agent_jar` parameter set to the - path of the installed [Java Instrumentation Agent]( - https://github.com/signalfx/splunk-otel-java) - (`/usr/lib/splunk-instrumentation/splunk-otel-javaagent.jar`). If the - `--deployment-environment VALUE` installer script option was specified, - the `deployment.environment=VALUE` resource attribute will be automatically - added to this file. - -See [Linux Java Auto Instrumentation](https://github.com/signalfx/splunk-otel-collector/tree/main/instrumentation#linux-java-auto-instrumentation) -for more details. - -**Note:** After any configuration changes, the Java application(s) on the host -need to be manually started/restarted to source the updated values from the -configuration file. +> The activation and configuration of Auto Instrumentation with the steps below +> will be applied ***globally*** on the host, either for ***all*** supported +> processes with the `--with-instrumentation` option, or for ***all*** +> supported `systemd` services with the `--with-systemd-instrumentation` +> option. Configuration of individual processes/services to override the global +> configuration will need to be managed separately and manually. + +- If the `--with-instrumentation` option was used: + - The `/etc/ld.so.preload` file will be automatically created/updated with the + default path to the installed instrumentation library + (`/usr/lib/splunk-instrumentation/libsplunk.so`). If necessary, custom + library paths can be manually added to this file. + - The `/usr/lib/splunk-instrumentation/instrumentation.conf` configuration + file will be automatically created to configure the provided Auto + Instrumentation agent(s), and can be manually configured for additional + resource attributes and other supported options. + - See [Configuration File]( + ../../instrumentation/libsplunk.md#configuration-file) for more details. + +- If the `--with-systemd-instrumentation` option was used: + - The `/usr/lib/systemd/system.conf.d/00-splunk-otel-auto-instrumentation.conf` + `systemd` drop-in file will be automatically created to include environment + variables that activate and configure the provided Auto Instrumentation + agent(s), and can be manually configured for additional environment + variables. + - See [Configuration](../../instrumentation/systemd.md#configuration) for + more details. + +**Note:** After any configuration changes, reboot the host or manually +start/restart the Java application(s) on the host for the changes to take +effect. #### Upgrade diff --git a/docs/getting-started/linux-manual.md b/docs/getting-started/linux-manual.md index 1f48f044b0..2a26121e54 100644 --- a/docs/getting-started/linux-manual.md +++ b/docs/getting-started/linux-manual.md @@ -69,7 +69,7 @@ installed on x86_64/amd64 platforms. apt-get update apt-get install -y splunk-otel-collector - # Optional: install Splunk OpenTelemetry Auto Instrumentation for Java + # Optional: install Splunk OpenTelemetry Auto Instrumentation apt-get install -y splunk-otel-auto-instrumentation ``` - RPM with `yum`: @@ -87,7 +87,7 @@ installed on x86_64/amd64 platforms. yum install -y splunk-otel-collector - # Optional: install Splunk OpenTelemetry Auto Instrumentation for Java + # Optional: install Splunk OpenTelemetry Auto Instrumentation yum install -y splunk-otel-auto-instrumentation ``` - RPM with `dnf`: @@ -105,7 +105,7 @@ installed on x86_64/amd64 platforms. dnf install -y splunk-otel-collector - # Optional: install Splunk OpenTelemetry Auto Instrumentation for Java + # Optional: install Splunk OpenTelemetry Auto Instrumentation dnf install -y splunk-otel-auto-instrumentation ``` - RPM with `zypper`: @@ -123,14 +123,14 @@ installed on x86_64/amd64 platforms. zypper install -y splunk-otel-collector - # Optional: install Splunk OpenTelemetry Auto Instrumentation for Java + # Optional: install Splunk OpenTelemetry Auto Instrumentation zypper install -y splunk-otel-auto-instrumentation ``` 1. See the [Collector Debian/RPM Post-Install Configuration](#collector-debianrpm-post-install-configuration) section. -1. If the optional Splunk OpenTelemetry Auto Instrumentation for Java package - was installed, see the [Auto Instrumentation Post-Install - Configuration](#auto-instrumentation-post-install-configuration) section. +1. If the optional Splunk OpenTelemetry Auto Instrumentation package was + installed, see the [Auto Instrumentation Post-Install Configuration]( + #auto-instrumentation-post-install-configuration) section. 1. If log collection is required, see the [Fluentd](#fluentd) section. 1. To upgrade the Collector, run the following commands: - Debian: @@ -165,10 +165,9 @@ installed on x86_64/amd64 platforms. sudo apt-get update sudo apt-get install --only-upgrade splunk-otel-auto-instrumentation ``` - **Note:** You may be prompted to keep or overwrite the configuration file - at `/usr/lib/splunk-instrumentation/instrumentation.conf`. Choosing to - overwrite will revert this file to the default file provided by the new - package. + **Note:** You may be prompted to keep or overwrite the configuration files + in the `/etc/splunk/zeroconfig` directory. Choosing to overwrite will + revert this file to the default file provided by the new package. - RPM: - `yum` ```sh @@ -181,8 +180,12 @@ installed on x86_64/amd64 platforms. - `zypper` ```sh sudo zypper refresh - sudo zypper update splunk-otel-instrumentation + sudo zypper update splunk-otel-auto-instrumentation ``` + **Note:** If the default configuration files in `/etc/splunk/zeroconfig` + have been modified after initial installation, the existing files will be + preserved and the files from the new package may be installed + with a `.rpmnew` extension. #### Collector Debian/RPM Packages @@ -317,35 +320,47 @@ and install it with the following commands (requires `root` privileges). ```sh sudo dpkg -i ``` - **Note:** You may be prompted to keep or overwrite the configuration file - at `/usr/lib/splunk-instrumentation/instrumentation.conf`. Choosing to - overwrite will revert this file to the default file provided by the new - package. + **Note:** You may be prompted to keep or overwrite the configuration files + in the `/etc/splunk/zeroconfig` directory. Choosing to overwrite will + revert this file to the default file provided by the new package. - RPM ```sh sudo rpm -Uvh ``` + **Note:** If the default configuration files in `/etc/splunk/zeroconfig` + have been modified after initial installation, the existing files will be + preserved and the files from the new package may be installed + with a `.rpmnew` extension. #### Auto Instrumentation Post-Install Configuration -- The `/etc/ld.so.preload` file will be automatically created/updated with the - default path to the installed instrumentation library - (`/usr/lib/splunk-instrumentation/libsplunk.so`). If necessary, custom - library paths can be manually added to this file. -- The `/usr/lib/splunk-instrumentation/instrumentation.conf` configuration file - can be manually configured for resource attributes and other parameters. By - default, this file will contain the `java_agent_jar` parameter set to the - path of the installed [Java Instrumentation Agent]( - https://github.com/signalfx/splunk-otel-java) - (`/usr/lib/splunk-instrumentation/splunk-otel-javaagent.jar`). - -See [Linux Java Auto Instrumentation](https://github.com/signalfx/splunk-otel-collector/tree/main/instrumentation#linux-java-auto-instrumentation) -for more details. - -**Note:** After installation/upgrade or any configuration changes, the Java -application(s) on the host need to be manually started/restarted for automatic -instrumentation to take effect and/or to source the updated values in the -configuration file. +The `splunk-otel-auto-instrumentation` deb/rpm package installs and supports +configuration for the following Auto Instrumentation agents: + +- [Java](https://docs.splunk.com/Observability/gdi/get-data-in/application/java/get-started.html) +- [Node.js](https://docs.splunk.com/Observability/en/gdi/get-data-in/application/nodejs/get-started.html) + +To manually activate and configure the Auto Instrumentation agents: +1. Check agent compatibility and requirements: + - [Java](https://docs.splunk.com/Observability/gdi/get-data-in/application/java/java-otel-requirements.html) + - [Node.js](https://docs.splunk.com/Observability/en/gdi/get-data-in/application/nodejs/nodejs-otel-requirements.html) +2. If Auto Instrumentation for Node.js is required, install the provided + `/usr/lib/splunk-instrumentation/splunk-otel-js.tgz` Node.js package with + `npm`. For example: + ```sh + sudo npm install --global /usr/lib/splunk-instrumentation/splunk-otel-js.tgz + ``` + > **Notes:** + > - Ensure that all Node.js applications/services to be instrumented have + > access to the installation path of the Node.js package. + > - On `arm64` architectures, it may be necessary to build/compile the + > Node.js package when installing with `npm`. Ensure that any required + > tools/libraries are installed on these systems, for example, + > `sudo apt-get install build-essential` on Debian-based systems or + > `sudo yum groupinstall 'Development Tools'` on RPM-based systems. +3. See [Activation and Configuration]( + ../../instrumentation/README.md#activation-and-configuration) for supported + methods and options. #### Fluentd 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 index fc6604f7c2..d26af49e16 100644 --- a/instrumentation/README.md +++ b/instrumentation/README.md @@ -1,181 +1,129 @@ -# 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 +# Splunk OpenTelemetry Zero Configuration Auto Instrumentation for Linux + +The **Splunk OpenTelemetry Zero Configuration Auto Instrumentation for Linux** Debian/RPM package +(`splunk-otel-auto-instrumentation`) installs Splunk OpenTelemetry Auto Instrumentation agents, the `libsplunk.so` +shared object library, and default/sample configuration files to automatically instrument applications and services to +capture and report distributed traces and metrics to the [Splunk OpenTelemetry Collector]( +https://docs.splunk.com/Observability/gdi/opentelemetry/opentelemetry.html), and then on to [Splunk APM]( +https://docs.splunk.com/Observability/apm/intro-to-apm.html). + +The `splunk-otel-auto-instrumentation` deb/rpm package installs and supports configuration of the following Auto +Instrumentation agents: + +- [Java](https://docs.splunk.com/Observability/gdi/get-data-in/application/java/get-started.html) +- [Node.js](https://docs.splunk.com/Observability/en/gdi/get-data-in/application/nodejs/get-started.html) + +For other languages or if the `splunk-otel-auto-instrumentation` deb/rpm package is not applicable for the target host +or applications/services, see [Instrument back-end applications to send spans to Splunk APM]( +https://docs.splunk.com/Observability/en/gdi/get-data-in/application/application.html). + +## Prerequisites/Requirements + +- Check agent compatibility and requirements: + - [Java](https://docs.splunk.com/Observability/gdi/get-data-in/application/java/java-otel-requirements.html) + - [Node.js](https://docs.splunk.com/Observability/en/gdi/get-data-in/application/nodejs/nodejs-otel-requirements.html) +- [Install and configure](https://docs.splunk.com/Observability/gdi/opentelemetry/install-linux.html) the Splunk + OpenTelemetry Collector. +- Debian or RPM based Linux distribution (amd64/x86_64 or arm64/aarch64). + +## Installation + +### Manual + +1. [Install and configure](https://docs.splunk.com/Observability/gdi/opentelemetry/install-linux.html) the Splunk + OpenTelemetry Collector +2. [Install](../docs/getting-started/linux-manual.md#auto-instrumentation-debianrpm-packages) the + `splunk-otel-auto-instrumentation` deb/rpm package +3. If Auto Instrumentation for Node.js is required, [install]( + ../docs/getting-started/linux-manual.md#auto-instrumentation-post-install-configuration) the provided + `/usr/lib/splunk-instrumentatgion/splunk-otel-js.tgz` Node.js package with `npm`. +4. [Activate and configure](#activation-and-configuration) Auto Instrumentation with the supported methods and options. + +## Activation and Configuration + +The following methods are supported to manually activate and configure Auto Instrumentation after installation of the +`splunk-otel-auto-instrumentation` deb/rpm package (requires `root` privileges): + +- [System-wide](#system-wide) +- [`Systemd` services only](#systemd-services-only) + +> **Note**: To prevent conflicts and duplicate traces/metrics, only one method should be activated on the target system. + +### System-wide + +1. Add the path of the provided `/usr/lib/splunk-instrumentation/libsplunk.so` shared object library to the + [`/etc/ld.so.preload`](https://man7.org/linux/man-pages/man8/ld.so.8.html#FILES) file to activate Auto + Instrumentation for ***all*** supported processes on the system. For example: + ``` + echo /usr/lib/splunk-instrumentation/libsplunk.so >> /etc/ld.so.preload + ``` +2. The default configuration files in the `/etc/splunk/zeroconfig` directory includes the required environment variables + to activate the respective agents with the default options: + - `/etc/splunk/zeroconfig/java.conf`: + ``` + JAVA_TOOL_OPTIONS=-javaagent:/usr/lib/splunk-instrumentation/splunk-otel-javaagent.jar + ``` + - `/etc/splunk/zeroconfig/node.conf`: + ``` + NODE_OPTIONS=-r @splunk/otel/instrument + ``` + Configuration of the respective agents is supported by the adding/updating the following environment variables in + each of these files (***any environment variable not in this list will be ignored***): + - `OTEL_EXPORTER_OTLP_ENDPOINT` + - `OTEL_RESOURCE_ATTRIBUTES` + - `OTEL_SERVICE_NAME` + - `SPLUNK_METRICS_ENABLED` + - `SPLUNK_PROFILER_ENABLED` + - `SPLUNK_PROFILER_MEMORY_ENABLED` + + Check the following for details about these environment variables and default values: + - [Java](https://docs.splunk.com/Observability/en/gdi/get-data-in/application/java/configuration/advanced-java-otel-configuration.html) + - [Node.js](https://docs.splunk.com/Observability/en/gdi/get-data-in/application/nodejs/configuration/advanced-nodejs-otel-configuration.html) +3. Reboot the system or restart the applications/services for any changes to take effect. The `libsplunk.so` shared + object library will then be preloaded for all subsequent processes and inject the environment variables from the + `/etc/splunk/zeroconfig` configuration files for Java and Node.js processes. + +### `Systemd` services only + +> **Note**: The following steps utilize a sample `systemd` drop-in file to activate/configure the provided agents for +> all `systemd` services via default environment variables. `Systemd` supports many options, methods, and paths for +> configuring environment variables at the system level or for individual services, and are not limited to the steps +> below. Before making any changes, it is recommended to consult the documentation specific to your Linux distribution +> or service, and check the existing configurations of the system and individual services for potential conflicts or to +> override an environment variable for a particular service. For general details about `systemd`, see the +> [`systemd` man page](https://www.freedesktop.org/software/systemd/man/index.html). + +1. Copy the provided sample `systemd` drop-in file + `/usr/lib/splunk-instrumentation/examples/systemd/00-splunk-otel-auto-instrumentation.conf` to the host's `systemd` + [drop-in configuration directory](https://www.freedesktop.org/software/systemd/man/systemd-system.conf.html) to + activate Auto Instrumentation for ***all*** supported applications running as `systemd` services. For example: + ``` + mkdir -p /usr/lib/systemd/system.conf.d/ && cp /usr/lib/splunk-instrumentation/examples/systemd/00-splunk-otel-auto-instrumentation.conf /usr/lib/systemd/system.conf.d/ + ``` + This file includes the required environment variables to activate the respective agents with the default options: + - Java: + ``` + DefaultEnvironment="JAVA_TOOL_OPTIONS=-javaagent:/usr/lib/splunk-instrumentation/splunk-otel-javaagent.jar" + ``` + - Node.js: + ``` + DefaultEnvironment="NODE_OPTIONS=-r @splunk/otel/instrument" + ``` +2. To configure the activated agents, add/update [`DefaultEnvironment`]( + https://www.freedesktop.org/software/systemd/man/systemd-system.conf.html#DefaultEnvironment=) within the target file + from the previous step for the desired environment variables. For example: + ``` + cat <> /usr/lib/systemd/system.conf.d/00-splunk-otel-auto-instrumentation.conf + DefaultEnvironment="OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4317" + DefaultEnvironment="OTEL_RESOURCE_ATTRIBUTES=deployment.environment=my_deployment_environment" + DefaultEnvironment="OTEL_SERVICE_NAME=my_service_name" + DefaultEnvironment="SPLUNK_METRICS_ENABLED=true" + DefaultEnvironment="SPLUNK_PROFILER_ENABLED=true" + DefaultEnvironment="SPLUNK_PROFILER_MEMORY_ENABLED=true" + EOH + ``` + Check the following for all supported environment variables and default values: + - [Java](https://docs.splunk.com/Observability/en/gdi/get-data-in/application/java/configuration/advanced-java-otel-configuration.html) + - [Node.js](https://docs.splunk.com/Observability/en/gdi/get-data-in/application/nodejs/configuration/advanced-nodejs-otel-configuration.html) +3. Reboot the system, or run `systemctl daemon-reload` and then restart the applicable `systemd` services for any + changes to take effect. 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..99eb693f79 100644 --- a/instrumentation/packaging/fpm/common.sh +++ b/instrumentation/packaging/fpm/common.sh @@ -24,16 +24,23 @@ PKG_DESCRIPTION="Splunk OpenTelemetry Auto Instrumentation" PKG_LICENSE="Apache 2.0" 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" +INSTALL_DIR="/usr/lib/splunk-instrumentation" +LIBSPLUNK_INSTALL_PATH="${INSTALL_DIR}/libsplunk.so" +JAVA_AGENT_INSTALL_PATH="${INSTALL_DIR}/splunk-otel-javaagent.jar" +CONFIG_DIR_REPO_PATH="${FPM_DIR}/etc/splunk/zeroconfig" +CONFIG_DIR_INSTALL_PATH="/etc/splunk/zeroconfig" +EXAMPLES_INSTALL_DIR="${INSTALL_DIR}/examples" +EXAMPLES_DIR="${FPM_DIR}/examples" JAVA_AGENT_RELEASE_PATH="${FPM_DIR}/../java-agent-release.txt" JAVA_AGENT_RELEASE_URL="https://github.com/signalfx/splunk-otel-java/releases/" +JAVA_AGENT_INSTALL_PATH="${INSTALL_DIR}/splunk-otel-javaagent.jar" + +NODEJS_AGENT_RELEASE_PATH="${FPM_DIR}/../nodejs-agent-release.txt" +NODEJS_AGENT_RELEASE_URL="https://github.com/signalfx/splunk-otel-js/releases/" +NODEJS_AGENT_INSTALL_PATH="${INSTALL_DIR}/splunk-otel-js.tgz" -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 )" @@ -64,23 +71,40 @@ download_java_agent() { curl -sfL "$dl_url" -o "$dest" } +download_nodejs_agent() { + local tag="$1" + local dest="$2" + local dl_url="$NODEJS_AGENT_RELEASE_URL/download/$tag/splunk-otel-${tag#v}.tgz" + + echo "Downloading $dl_url ..." + mkdir -p "$( dirname $dest )" + curl -sfL "$dl_url" -o "$dest" +} + setup_files_and_permissions() { - local libsplunk="$1" - local java_agent="$2" - local buildroot="$3" + local arch="$1" + local buildroot="$2" + local libsplunk="$REPO_DIR/instrumentation/dist/libsplunk_${arch}.so" + local java_agent_release="$(cat "$JAVA_AGENT_RELEASE_PATH")" + local nodejs_agent_release="$(cat "$NODEJS_AGENT_RELEASE_PATH")" mkdir -p "$buildroot/$(dirname $LIBSPLUNK_INSTALL_PATH)" cp -f "$libsplunk" "$buildroot/$LIBSPLUNK_INSTALL_PATH" - sudo chown root:root "$buildroot/$LIBSPLUNK_INSTALL_PATH" sudo chmod 755 "$buildroot/$LIBSPLUNK_INSTALL_PATH" - mkdir -p "$buildroot/$(dirname $JAVA_AGENT_INSTALL_PATH)" - cp -f "$java_agent" "$buildroot/$JAVA_AGENT_INSTALL_PATH" - sudo chown root:root "$buildroot/$JAVA_AGENT_INSTALL_PATH" + download_java_agent "$java_agent_release" "${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" + download_nodejs_agent "$nodejs_agent_release" "${buildroot}/${NODEJS_AGENT_INSTALL_PATH}" + sudo chmod 644 "$buildroot/$NODEJS_AGENT_INSTALL_PATH" + + mkdir -p "$buildroot/$CONFIG_DIR_INSTALL_PATH" + cp -rf "$CONFIG_DIR_REPO_PATH"/* "$buildroot/$CONFIG_DIR_INSTALL_PATH"/ + sudo chmod -R 644 "$buildroot/$CONFIG_DIR_INSTALL_PATH" + + mkdir -p "$buildroot/$INSTALL_DIR" + cp -rf "$EXAMPLES_DIR" "$buildroot/$INSTALL_DIR/" + sudo chmod -R 644 "$buildroot/$EXAMPLES_INSTALL_DIR" + + sudo chown -R root:root "$buildroot" } diff --git a/instrumentation/packaging/fpm/deb/build.sh b/instrumentation/packaging/fpm/deb/build.sh index 457c2ac9aa..5dd09094ac 100755 --- a/instrumentation/packaging/fpm/deb/build.sh +++ b/instrumentation/packaging/fpm/deb/build.sh @@ -22,20 +22,15 @@ SCRIPT_DIR="$( cd "$( dirname ${BASH_SOURCE[0]} )" && pwd )" VERSION="${1:-}" ARCH="${2:-amd64}" OUTPUT_DIR="${3:-$REPO_DIR/instrumentation/dist}" -LIBSPLUNK_PATH="$REPO_DIR/instrumentation/dist/libsplunk_${ARCH}.so" -JAVA_AGENT_PATH="$REPO_DIR/instrumentation/dist/splunk-otel-javaagent.jar" -JAVA_AGENT_RELEASE="$(cat $JAVA_AGENT_RELEASE_PATH)" if [[ -z "$VERSION" ]]; then VERSION="$( get_version )" fi VERSION="${VERSION#v}" -download_java_agent "$JAVA_AGENT_RELEASE" "$JAVA_AGENT_PATH" - buildroot="$(mktemp -d)" -setup_files_and_permissions "$LIBSPLUNK_PATH" "$JAVA_AGENT_PATH" "$buildroot" +setup_files_and_permissions "$ARCH" "$buildroot" mkdir -p "$OUTPUT_DIR" @@ -48,12 +43,11 @@ sudo fpm -s dir -t deb -n "$PKG_NAME" -v "$VERSION" -f -p "$OUTPUT_DIR" \ --architecture "$ARCH" \ --deb-dist "stable" \ --deb-use-file-permissions \ - --after-install "$POSTINSTALL_PATH" \ --before-remove "$PREUNINSTALL_PATH" \ --deb-no-default-config-files \ --depends sed \ --depends grep \ - --config-files "$CONFIG_INSTALL_PATH" \ + --config-files "$CONFIG_DIR_INSTALL_PATH" \ "$buildroot/"=/ dpkg -c "${OUTPUT_DIR}/${PKG_NAME}_${VERSION}_${ARCH}.deb" diff --git a/instrumentation/packaging/fpm/etc/splunk/zeroconfig/java.conf b/instrumentation/packaging/fpm/etc/splunk/zeroconfig/java.conf new file mode 100644 index 0000000000..cb41b0dda2 --- /dev/null +++ b/instrumentation/packaging/fpm/etc/splunk/zeroconfig/java.conf @@ -0,0 +1 @@ +JAVA_TOOL_OPTIONS=-javaagent:/usr/lib/splunk-instrumentation/splunk-otel-javaagent.jar diff --git a/instrumentation/packaging/fpm/etc/splunk/zeroconfig/node.conf b/instrumentation/packaging/fpm/etc/splunk/zeroconfig/node.conf new file mode 100644 index 0000000000..139418d771 --- /dev/null +++ b/instrumentation/packaging/fpm/etc/splunk/zeroconfig/node.conf @@ -0,0 +1 @@ +NODE_OPTIONS=-r @splunk/otel/instrument diff --git a/instrumentation/packaging/fpm/examples/systemd/00-splunk-otel-auto-instrumentation.conf b/instrumentation/packaging/fpm/examples/systemd/00-splunk-otel-auto-instrumentation.conf new file mode 100644 index 0000000000..5199d821e6 --- /dev/null +++ b/instrumentation/packaging/fpm/examples/systemd/00-splunk-otel-auto-instrumentation.conf @@ -0,0 +1,54 @@ +# Copyright Splunk Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Sample systemd drop-in file to activate and configure Splunk OpenTelemetry Auto Instrumentation for Java and Node.js +# https://docs.splunk.com/Observability/gdi/get-data-in/application/java/get-started.html +# https://docs.splunk.com/Observability/gdi/get-data-in/application/nodejs/get-started.html + +# To use this file to activate/configure auto instrumentation for all supported applications running as systemd +# services (requires root privileges): +# 1. Check agent compatibility and requirements: +# - Java: https://docs.splunk.com/Observability/gdi/get-data-in/application/java/java-otel-requirements.html for +# - Node.js: https://docs.splunk.com/Observability/gdi/get-data-in/application/nodejs/nodejs-otel-requirements.html +# 2. Check supported environment variables and defaults: +# - Java: https://docs.splunk.com/Observability/gdi/get-data-in/application/java/configuration/advanced-java-otel-configuration.html +# - Node.js: https://docs.splunk.com/Observability/gdi/get-data-in/application/nodejs/configuration/advanced-nodejs-otel-configuration.html +# 3. If Node.js is required, install the provided Node.js auto instrumentation package with npm and any dependencies. +# For example: +# $ sudo npm install --global /usr/lib/splunk-instrumentation/splunk-otel-js.tgz +# Important: Ensure that all Node.js services to be instrumented has access to the installation path. +# 4. Add/Update the DefaultEnvironment entries below for the desired environment variables and values +# 5. Copy this file to the systemd configuration directory, e.g. /usr/lib/systemd/system.conf.d/ +# 6. Reboot the system or run the following commands to restart the applicable service(s) for any changes to take effect: +# $ sudo systemctl daemon-reload +# $ sudo systemctl restart # replace "" and run for each applicable service + +# See https://www.freedesktop.org/software/systemd/man/systemd-system.conf.html for general information +# about systemd configuration and other supported options. + +[Manager] +# Required to activate Splunk OpenTelemetry Auto Instrumentation for Java +DefaultEnvironment="JAVA_TOOL_OPTIONS=-javaagent:/usr/lib/splunk-instrumentation/splunk-otel-javaagent.jar" + +# Required to activate Splunk OpenTelemetry Auto Instrumentation for Node.js +DefaultEnvironment="NODE_OPTIONS=-r @splunk/otel/instrument" + +# Examples of common configuration options. +# The environment variables defined in this file will apply to all activated agents. +#DefaultEnvironment="OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4317" +#DefaultEnvironment="OTEL_RESOURCE_ATTRIBUTES=deployment.environment=my_deployment_environment" +#DefaultEnvironment="OTEL_SERVICE_NAME=my_service_name" +#DefaultEnvironment="SPLUNK_METRICS_ENABLED=true" +#DefaultEnvironment="SPLUNK_PROFILER_ENABLED=true" +#DefaultEnvironment="SPLUNK_PROFILER_MEMORY_ENABLED=true" diff --git a/instrumentation/packaging/fpm/postinstall.sh b/instrumentation/packaging/fpm/postinstall.sh deleted file mode 100644 index d935680009..0000000000 --- a/instrumentation/packaging/fpm/postinstall.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/sh - -# Copyright Splunk Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -PRELOAD_PATH="/etc/ld.so.preload" -LIBSPLUNK_PATH="/usr/lib/splunk-instrumentation/libsplunk.so" - -if [ -f "$PRELOAD_PATH" ]; then - if ! grep -q "$LIBSPLUNK_PATH" "$PRELOAD_PATH"; then - # backup existing file with timestamp - if command -v rpm >/dev/null 2>&1; then - # need to escape '%' for rpm macros - ts="$(date '+%%Y%%m%%d-%%H%%M%%S')" - else - ts="$(date '+%Y%m%d-%H%M%S')" - fi - echo "Saving $PRELOAD_PATH as ${PRELOAD_PATH}.bak.${ts}" - cp "$PRELOAD_PATH" "${PRELOAD_PATH}.bak.${ts}" - echo "Adding $LIBSPLUNK_PATH to $PRELOAD_PATH" - echo "$LIBSPLUNK_PATH" >> "$PRELOAD_PATH" - fi -else - echo "Adding $LIBSPLUNK_PATH to $PRELOAD_PATH" - echo "$LIBSPLUNK_PATH" >> "$PRELOAD_PATH" -fi diff --git a/instrumentation/packaging/fpm/rpm/build.sh b/instrumentation/packaging/fpm/rpm/build.sh index 6bfc96e621..61609422eb 100755 --- a/instrumentation/packaging/fpm/rpm/build.sh +++ b/instrumentation/packaging/fpm/rpm/build.sh @@ -22,9 +22,6 @@ SCRIPT_DIR="$( cd "$( dirname ${BASH_SOURCE[0]} )" && pwd )" VERSION="${1:-}" ARCH="${2:-amd64}" OUTPUT_DIR="${3:-$REPO_DIR/instrumentation/dist}" -LIBSPLUNK_PATH="$REPO_DIR/instrumentation/dist/libsplunk_${ARCH}.so" -JAVA_AGENT_PATH="$REPO_DIR/instrumentation/dist/splunk-otel-javaagent.jar" -JAVA_AGENT_RELEASE="$(cat $JAVA_AGENT_RELEASE_PATH)" if [[ -z "$VERSION" ]]; then VERSION="$( get_version )" @@ -34,11 +31,9 @@ fi VERSION="${VERSION/'-'/'~'}" VERSION="${VERSION#v}" -download_java_agent "$JAVA_AGENT_RELEASE" "$JAVA_AGENT_PATH" - buildroot="$(mktemp -d)" -setup_files_and_permissions "$LIBSPLUNK_PATH" "$JAVA_AGENT_PATH" "$buildroot" +setup_files_and_permissions "$ARCH" "$buildroot" mkdir -p "$OUTPUT_DIR" @@ -58,11 +53,10 @@ sudo fpm -s dir -t rpm -n "$PKG_NAME" -v "$VERSION" -f -p "$OUTPUT_DIR" \ --rpm-rpmbuild-define "_build_id_links none" \ --rpm-summary "$PKG_DESCRIPTION" \ --rpm-use-file-permissions \ - --rpm-posttrans "$POSTINSTALL_PATH" \ --before-remove "$PREUNINSTALL_PATH" \ --depends sed \ --depends grep \ - --config-files "$CONFIG_INSTALL_PATH" \ + --config-files "$CONFIG_DIR_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/packaging/nodejs-agent-release.txt b/instrumentation/packaging/nodejs-agent-release.txt new file mode 100644 index 0000000000..6bd4da99c9 --- /dev/null +++ b/instrumentation/packaging/nodejs-agent-release.txt @@ -0,0 +1 @@ +v2.4.4 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..497b2f0d10 --- /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..f9dc34d545 --- /dev/null +++ b/instrumentation/tests/java/Dockerfile @@ -0,0 +1,21 @@ +ARG BASE=busybox +FROM $BASE + +COPY Main.java . + +RUN javac Main.java && \ + jar cfe Main.jar Main Main.class + +RUN mkdir -p /etc/splunk/zerconfig + +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..34606e5565 --- /dev/null +++ b/instrumentation/tests/nodejs/Dockerfile @@ -0,0 +1,14 @@ +ARG BASE=busybox +FROM $BASE + +COPY index.js . + +RUN mkdir -p /etc/splunk/zeroconfig + +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 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 diff --git a/internal/buildscripts/packaging/installer/install.sh b/internal/buildscripts/packaging/installer/install.sh index edbab6cc83..522511425b 100755 --- a/internal/buildscripts/packaging/installer/install.sh +++ b/internal/buildscripts/packaging/installer/install.sh @@ -113,6 +113,7 @@ instrumentation_config_path="/usr/lib/splunk-instrumentation/instrumentation.con instrumentation_so_path="/usr/lib/splunk-instrumentation/libsplunk.so" instrumentation_jar_path="/usr/lib/splunk-instrumentation/splunk-otel-javaagent.jar" generate_service_name="true" +systemd_instrumentation_config_path="/usr/lib/systemd/system.conf.d/00-splunk-otel-auto-instrumentation.conf" service_name="" disable_telemetry="false" enable_profiler="false" @@ -468,15 +469,19 @@ disable_preload() { } create_instrumentation_config() { - local deployment_environment="$1" local version="$( get_package_version splunk-otel-auto-instrumentation )" local resource_attributes="splunk.zc.method=splunk-otel-auto-instrumentation-${version}" + if [ -n "$deployment_environment" ]; then + resource_attributes="${resource_attributes},deployment.environment=${deployment_environment}" + fi + backup_file "$instrumentation_config_path" echo "Creating ${instrumentation_config_path}" cat < $instrumentation_config_path java_agent_jar=${instrumentation_jar_path} +resource_attributes=${resource_attributes} generate_service_name=${generate_service_name} disable_telemetry=${disable_telemetry} enable_profiler=${enable_profiler} @@ -484,15 +489,40 @@ enable_profiler_memory=${enable_profiler_memory} enable_metrics=${enable_metrics} EOH + if [ -n "$service_name" ]; then + echo "service_name=${service_name}" >> $instrumentation_config_path + fi +} + +create_systemd_instrumentation_config() { + local otlp_endpoint="$1" + local version="$( get_package_version splunk-otel-auto-instrumentation )" + local resource_attributes="splunk.zc.method=splunk-otel-auto-instrumentation-${version}-systemd" + if [ -n "$deployment_environment" ]; then resource_attributes="${resource_attributes},deployment.environment=${deployment_environment}" fi - echo "resource_attributes=${resource_attributes%,}" >> $instrumentation_config_path + mkdir -p "$(dirname $systemd_instrumentation_config_path)" + + backup_file "$systemd_instrumentation_config_path" + + echo "Creating ${systemd_instrumentation_config_path}" + cat < $systemd_instrumentation_config_path +[Manager] +DefaultEnvironment="JAVA_TOOL_OPTIONS=-javaagent:${instrumentation_jar_path}" +DefaultEnvironment="OTEL_RESOURCE_ATTRIBUTES=${resource_attributes}" +DefaultEnvironment="SPLUNK_PROFILER_ENABLED=${enable_profiler}" +DefaultEnvironment="SPLUNK_PROFILER_MEMORY_ENABLED=${enable_profiler_memory}" +DefaultEnvironment="SPLUNK_METRICS_ENABLED=${enable_metrics}" +DefaultEnvironment="OTEL_EXPORTER_OTLP_ENDPOINT=${otlp_endpoint}" +EOH if [ -n "$service_name" ]; then - echo "service_name=${service_name}" >> $instrumentation_config_path + echo "DefaultEnvironment=\"OTEL_SERVICE_NAME=${service_name}\"" >> $systemd_instrumentation_config_path fi + + systemctl daemon-reload } install() { @@ -597,6 +627,12 @@ uninstall() { fi apt-get purge -y $pkg 2>&1 echo "Successfully removed the $pkg package" + if [ "$pkg" = "splunk-otel-auto-instrumentation" ] && [ -f "$systemd_instrumentation_config_path" ]; then + backup_file "$systemd_instrumentation_config_path" + echo "Removing ${systemd_instrumentation_config_path}" + rm -f "$systemd_instrumentation_config_path" + systemctl daemon-reload + fi else agent_path="$( command -v agent )" echo "$agent_path exists but the $pkg package is not installed" >&2 @@ -617,6 +653,12 @@ uninstall() { zypper remove -y $pkg fi echo "Successfully removed the $pkg package" + if [ "$pkg" = "splunk-otel-auto-instrumentation" ] && [ -f "$systemd_instrumentation_config_path" ]; then + backup_file "$systemd_instrumentation_config_path" + echo "Removing ${systemd_instrumentation_config_path}" + rm -f "$systemd_instrumentation_config_path" + systemctl daemon-reload + fi else agent_path="$( command -v agent )" echo "$agent_path exists but the $pkg package is not installed" >&2 @@ -706,16 +748,28 @@ Auto Instrumentation: --with[out]-instrumentation Whether to install the splunk-otel-auto-instrumentation package and add the libsplunk.so shared object library to /etc/ld.so.preload to enable auto instrumentation for all supported processes on the host. + Cannot be combined with the '--with-systemd-instrumentation' option. (default: --without-instrumentation) + --with[out]-systemd-instrumentation Whether to install the splunk-otel-auto-instrumentation package and configure a + systemd drop-in file to enable auto instrumentation for all supported + applications running as systemd services. + Cannot be combined with the '--with-instrumentation' option. + (default: --without-systemd-instrumentation) --deployment-environment Set the 'deployment.environment' resource attribute to the specified value. If not specified, the "Environment" in the Splunk APM UI will appear as "unknown" for the auto instrumented application(s). - Only applicable if the '--with-instrumentation' option is also specified. + Only applicable if the '--with-instrumentation' or + '--with-systemd-instrumentation' option is also specified. (default: empty) --service-name Override the auto-generated service names for all instrumented Java applications on this host with ''. - Only applicable if the '--with-instrumentation' option is also specified. + Only applicable if the '--with-instrumentation' or + '--with-systemd-instrumentation' option is also specified. (default: empty) + --otlp-endpoint Set the OTLP gRPC endpoint for captured traces. + Only applicable if the '--with-systemd-instrumentation' option is also specified. + (default: http://LISTEN_INTERFACE:4317 where LISTEN_INTERFACE is the value from + the --listen-interface option if specified, or "127.0.0.1" otherwise) --[no-]generate-service-name Specify '--no-generate-service-name' to prevent the preloader from setting the OTEL_SERVICE_NAME environment variable. Only applicable if the '--with-instrumentation' option is also specified. @@ -725,16 +779,20 @@ Auto Instrumentation: Only applicable if the '--with-instrumentation' option is also specified. (default: --enable-telemetry) --[enable|disable]-profiler Enable or disable AlwaysOn CPU Profiling. - Only applicable if the '--with-instrumentation' option is also specified. + Only applicable if the '--with-instrumentation' or + '--with-systemd-instrumentation' option is also specified. (default: --disable-profiler) --[enable|disable]-profiler-memory Enable or disable AlwaysOn Memory Profiling. - Only applicable if the '--with-instrumentation' option is also specified. + Only applicable if the '--with-instrumentation' or + '--with-systemd-instrumentation' option is also specified. (default: --disable-profiler-memory) --[enable|disable]-metrics Enable or disable exporting Micrometer metrics. - Only applicable if the '--with-instrumentation' option is also specified. + Only applicable if the '--with-instrumentation' or + '--with-systemd-instrumentation' option is also specified. (default: --disable-metrics) --instrumentation-version The splunk-otel-auto-instrumentation package version to install. - Only applicable if the '--with-instrumentation' option is also specified. + Only applicable if the '--with-instrumentation' or + '--with-systemd-instrumentation' option is also specified. (default: $default_instrumentation_version) Uninstall: @@ -888,9 +946,11 @@ parse_args_and_install() { local skip_collector_repo="false" local skip_fluentd_repo="false" local with_instrumentation="false" + local with_systemd_instrumentation="false" local instrumentation_version="$default_instrumentation_version" local deployment_environment="$default_deployment_environment" local discovery= + local otlp_endpoint="" while [ -n "${1-}" ]; do case $1 in @@ -995,6 +1055,12 @@ parse_args_and_install() { --without-instrumentation) with_instrumentation="false" ;; + --with-systemd-instrumentation) + with_systemd_instrumentation="true" + ;; + --without-systemd-instrumentation) + with_systemd_instrumentation="false" + ;; --instrumentation-version) instrumentation_version="$2" shift 1 @@ -1007,6 +1073,10 @@ parse_args_and_install() { service_name="$2" shift 1 ;; + --otlp-endpoint) + otlp_endpoint="$2" + shift 1 + ;; --generate-service-name) generate_service_name="true" ;; @@ -1067,6 +1137,11 @@ parse_args_and_install() { exit 0 fi + if [ "$with_instrumentation" = "true" ] && [ "$with_systemd_instrumentation" = "true" ]; then + echo "ERROR: Both --with-instrumentation and --with-systemd-instrumentation options were specified. Only one option is allowed." >&2 + exit 1 + fi + if [ -z "$access_token" ]; then access_token=$(request_access_token) fi @@ -1091,7 +1166,7 @@ parse_args_and_install() { td_agent_version="" fi - if [ "$with_instrumentation" != "true" ]; then + if [ "$with_instrumentation" != "true" ] && [ "$with_systemd_instrumentation" != "true" ]; then instrumentation_version="" fi @@ -1099,6 +1174,14 @@ parse_args_and_install() { trace_url="${ingest_url}/v2/trace" fi + if [ -z "$otlp_endpoint" ]; then + if [ -n "$listen_interface" ]; then + otlp_endpoint="http://${listen_interface}:4317" + else + otlp_endpoint="http://127.0.0.1:4317" + fi + fi + check_support ensure_not_installed "$with_fluentd" "$with_instrumentation" @@ -1134,6 +1217,7 @@ parse_args_and_install() { fi echo " AlwaysOn Profiling enabled: $enable_profiler" echo " AlwaysOn Memory Profiling enabled: $enable_profiler_memory" + echo " OTLP Endpoint: $otlp_endpoint" fi echo @@ -1147,7 +1231,11 @@ parse_args_and_install() { if [ "$with_instrumentation" = "true" ]; then # add libsplunk.so to /etc/ld.so.preload if it was not added automatically by the instrumentation package enable_preload - create_instrumentation_config "$deployment_environment" + create_instrumentation_config + elif [ "$with_systemd_instrumentation" = "true" ]; then + # remove libsplunk.so from /etc/ld.so.preload if it was added automatically by the instrumentation package + disable_preload + create_systemd_instrumentation_config "$otlp_endpoint" fi create_user_group "$service_user" "$service_group" @@ -1305,6 +1393,15 @@ The configuration file is located at $instrumentation_config_path. Reboot the system or restart the Java application(s) for auto instrumentation to take effect. +EOH + elif [ "$with_systemd_instrumentation" = "true" ]; then + cat <> {PRELOAD_PATH}'") # run installer script @@ -315,7 +349,7 @@ def test_installer_with_instrumentation_default(distro, arch): time.sleep(5) # verify env file created with configured parameters - verify_env_file(container) + verify_env_file(container, config_path=custom_config) verify_config_file(container, PRELOAD_PATH, "# This line should be preserved", None) @@ -328,22 +362,40 @@ def test_installer_with_instrumentation_default(distro, arch): else: assert container.exec_run("rpm -q splunk-otel-auto-instrumentation").exit_code == 0 - # verify libsplunk.so was added to /etc/ld.so.preload - verify_config_file(container, PRELOAD_PATH, LIBSPLUNK_PATH, None) - - zc_method = r"splunk-otel-auto-instrumentation-\d+\.\d+\.\d+" - attributes = rf"splunk\.zc\.method={zc_method}" + config_attributes = rf"splunk\.zc\.method={zc_method}" - # verify default options - verify_config_file(container, INSTR_CONF_PATH, "java_agent_jar", JAVA_AGENT_PATH) - verify_config_file(container, INSTR_CONF_PATH, "disable_telemetry", "false") - verify_config_file(container, INSTR_CONF_PATH, "enable_profiler", "false") - verify_config_file(container, INSTR_CONF_PATH, "enable_profiler_memory", "false") - verify_config_file(container, INSTR_CONF_PATH, "enable_metrics", "false") - verify_config_file(container, INSTR_CONF_PATH, "resource_attributes", attributes) + if method == "libsplunk": + # verify libsplunk.so was added to /etc/ld.so.preload + verify_config_file(container, PRELOAD_PATH, LIBSPLUNK_PATH, None) - # verify service name is not set - verify_config_file(container, INSTR_CONF_PATH, "service_name", ".*", exists=False) + # verify default options + verify_config_file(container, config_path, "java_agent_jar", JAVA_AGENT_PATH) + verify_config_file(container, config_path, "resource_attributes", config_attributes) + verify_config_file(container, config_path, "disable_telemetry", "false") + verify_config_file(container, config_path, "enable_profiler", "false") + verify_config_file(container, config_path, "enable_profiler_memory", "false") + verify_config_file(container, config_path, "enable_metrics", "false") + verify_config_file(container, config_path, "service_name", ".*", exists=False) + else: + # verify libsplunk.so was not added to /etc/ld.so.preload + verify_config_file(container, PRELOAD_PATH, f".*{LIBSPLUNK_PATH}.*", None, exists=False) + + # verify default options + verify_config_file(container, config_path, "JAVA_TOOL_OPTIONS", f"-javaagent:{JAVA_AGENT_PATH}") + verify_config_file(container, config_path, "OTEL_RESOURCE_ATTRIBUTES", config_attributes) + verify_config_file(container, config_path, "SPLUNK_PROFILER_ENABLED", "false") + verify_config_file(container, config_path, "SPLUNK_PROFILER_MEMORY_ENABLED", "false") + verify_config_file(container, config_path, "SPLUNK_METRICS_ENABLED", "false") + verify_config_file(container, config_path, "OTEL_EXPORTER_OTLP_ENDPOINT", "http://127.0.0.1:4317") + verify_config_file(container, config_path, "OTEL_SERVICE_NAME", ".*", exists=False) + + tomcat_attributes = { + r"telemetry\.sdk\.language": r"Str\(java\)", + r"service\.name": rf"Str\({service_name}\)", + r"splunk\.zc\.method": rf"Str\({zc_method}\)", + } + + verify_app_instrumentation(container, "tomcat", method, tomcat_attributes) verify_uninstall(container, distro) @@ -351,37 +403,54 @@ def test_installer_with_instrumentation_default(distro, arch): verify_config_file(container, PRELOAD_PATH, f".*{LIBSPLUNK_PATH}.*", None, exists=False) verify_config_file(container, PRELOAD_PATH, "# This line should be preserved", None) + # verify the systemd config file was not created or was deleted + run_container_cmd(container, f"test ! -f {SYSTEMD_CONFIG_PATH}") + @pytest.mark.installer @pytest.mark.instrumentation @pytest.mark.parametrize( "distro", - [pytest.param(distro, marks=pytest.mark.deb) for distro in DEB_DISTROS] - + [pytest.param(distro, marks=pytest.mark.rpm) for distro in RPM_DISTROS], + [pytest.param(distro, marks=pytest.mark.deb) for distro in TOMCAT_DEB_DISTROS] + + [pytest.param(distro, marks=pytest.mark.rpm) for distro in TOMCAT_RPM_DISTROS], ) @pytest.mark.parametrize("arch", ["amd64", "arm64"]) -def test_installer_with_instrumentation_custom(distro, arch): +@pytest.mark.parametrize("method", ["libsplunk", "systemd"]) +def test_installer_with_instrumentation_custom(distro, arch, method): if distro == "opensuse-12" and arch == "arm64": pytest.skip("opensuse-12 arm64 no longer supported") - environment = "test-environment" - service_name = "test-service" + service_name = f"service_name_from_{method}" + environment = f"deployment_environment_from_{method}" + zc_method = r"splunk-otel-auto-instrumentation-0\.81\.0" + + if method == "libsplunk": + config_path = INSTR_CONF_PATH + else: + config_path = SYSTEMD_CONFIG_PATH + zc_method = f"{zc_method}-systemd" + + custom_config = "/etc/my-custom-config.yaml" install_cmd = " ".join(( get_installer_cmd(), - "--with-instrumentation", + "--with-systemd-instrumentation" if method == "systemd" else "--with-instrumentation", "--instrumentation-version 0.81.0", - f"--deployment-environment {environment}", + f"--collector-config {custom_config}", + f"--deployment-environment deployment_environment_from_{method}", "--disable-telemetry", - f"--service-name {service_name}", + f"--service-name service_name_from_{method}", "--enable-profiler", "--enable-profiler-memory", "--enable-metrics", + "--listen-interface 0.0.0.0", + "--otlp-endpoint http://127.0.0.1:4317", )) print(f"Testing installation on {distro} from {STAGE} stage ...") - with run_distro_container(distro, arch=arch) as container: + with run_distro_container(distro, dockerfile=get_tomcat_dockerfile(distro), arch=arch) as container: copy_file_into_container(container, INSTALLER_PATH, "/test/install.sh") + copy_file_into_container(container, CUSTOM_COLLECTOR_CONFIG, custom_config) run_container_cmd(container, f"sh -c 'echo \"# This line should be preserved\" >> {PRELOAD_PATH}'") # run installer script @@ -389,7 +458,7 @@ def test_installer_with_instrumentation_custom(distro, arch): time.sleep(5) # verify env file created with configured parameters - verify_env_file(container) + verify_env_file(container, config_path=custom_config) verify_config_file(container, PRELOAD_PATH, "# This line should be preserved", None) @@ -402,23 +471,51 @@ def test_installer_with_instrumentation_custom(distro, arch): else: assert container.exec_run("rpm -q splunk-otel-auto-instrumentation").exit_code == 0 - # verify libsplunk.so was added to /etc/ld.so.preload - verify_config_file(container, PRELOAD_PATH, LIBSPLUNK_PATH, None) - - zc_method = r"splunk-otel-auto-instrumentation-0\.81\.0" - attributes = rf"splunk\.zc\.method={zc_method},deployment\.environment={environment}" - - # verify configured options - verify_config_file(container, INSTR_CONF_PATH, "java_agent_jar", JAVA_AGENT_PATH) - verify_config_file(container, INSTR_CONF_PATH, "disable_telemetry", "true") - verify_config_file(container, INSTR_CONF_PATH, "enable_profiler", "true") - verify_config_file(container, INSTR_CONF_PATH, "enable_profiler_memory", "true") - verify_config_file(container, INSTR_CONF_PATH, "enable_metrics", "true") - verify_config_file(container, INSTR_CONF_PATH, "resource_attributes", attributes) - verify_config_file(container, INSTR_CONF_PATH, "service_name", service_name) + config_attributes = ",".join(( + rf"splunk\.zc\.method={zc_method}", + rf"deployment\.environment={environment}", + )) + + if method == "libsplunk": + # verify libsplunk.so was added to /etc/ld.so.preload + verify_config_file(container, PRELOAD_PATH, LIBSPLUNK_PATH, None) + + # verify configured options + verify_config_file(container, config_path, "java_agent_jar", JAVA_AGENT_PATH) + verify_config_file(container, config_path, "resource_attributes", config_attributes) + verify_config_file(container, config_path, "disable_telemetry", "true") + verify_config_file(container, config_path, "enable_profiler", "true") + verify_config_file(container, config_path, "enable_profiler_memory", "true") + verify_config_file(container, config_path, "enable_metrics", "true") + verify_config_file(container, config_path, "service_name", service_name) + else: + # verify libsplunk.so was not added to /etc/ld.so.preload + verify_config_file(container, PRELOAD_PATH, f".*{LIBSPLUNK_PATH}.*", None, exists=False) + + # verify configured options + verify_config_file(container, config_path, "JAVA_TOOL_OPTIONS", f"-javaagent:{JAVA_AGENT_PATH}") + verify_config_file(container, config_path, "OTEL_RESOURCE_ATTRIBUTES", config_attributes) + verify_config_file(container, config_path, "SPLUNK_PROFILER_ENABLED", "true") + verify_config_file(container, config_path, "SPLUNK_PROFILER_MEMORY_ENABLED", "true") + verify_config_file(container, config_path, "SPLUNK_METRICS_ENABLED", "true") + verify_config_file(container, config_path, "OTEL_EXPORTER_OTLP_ENDPOINT", "http://127.0.0.1:4317") + verify_config_file(container, config_path, "OTEL_SERVICE_NAME", service_name) + + tomcat_attributes = { + r"telemetry\.sdk\.language": r"Str\(java\)", + r"service\.name": rf"Str\({service_name}\)", + r"deployment\.environment": rf"Str\({environment}\)", + r"com\.splunk\.sourcetype": r"Str\(otel\.profiling\)", + r"splunk\.zc\.method": rf"Str\({zc_method}\)", + } + + verify_app_instrumentation(container, "tomcat", method, tomcat_attributes) verify_uninstall(container, distro) # verify libsplunk.so was removed from /etc/ld.so.preload verify_config_file(container, PRELOAD_PATH, f".*{LIBSPLUNK_PATH}.*", None, exists=False) verify_config_file(container, PRELOAD_PATH, "# This line should be preserved", None) + + # verify the systemd config file was not created or was deleted + run_container_cmd(container, f"test ! -f {SYSTEMD_CONFIG_PATH}") diff --git a/internal/buildscripts/packaging/tests/instrumentation/__init__.py b/internal/buildscripts/packaging/tests/instrumentation/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/internal/buildscripts/packaging/tests/instrumentation/config.yaml b/internal/buildscripts/packaging/tests/instrumentation/config.yaml new file mode 100755 index 0000000000..30fac53b0f --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/config.yaml @@ -0,0 +1,25 @@ +receivers: + signalfx: + endpoint: 0.0.0.0:9943 + otlp: + protocols: + grpc: + endpoint: 0.0.0.0:4317 + http: + endpoint: 0.0.0.0:4318 + +exporters: + logging: + verbosity: detailed + +service: + pipelines: + metrics: + receivers: [signalfx, otlp] + exporters: [logging] + logs: + receivers: [otlp] + exporters: [logging] + traces: + receivers: [otlp] + exporters: [logging] diff --git a/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.debian-bookworm b/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.debian-bookworm new file mode 100644 index 0000000000..c696b4dfc1 --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.debian-bookworm @@ -0,0 +1,35 @@ +# A debian image with systemd enabled. Must be run with: +# `-d --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro` flags +FROM tomcat:9-jre8 as tomcat + +FROM debian:bookworm + +ENV DEBIAN_FRONTEND noninteractive + +RUN apt-get update &&\ + apt-get install -yq ca-certificates curl procps python3 systemd wget + +ENV container docker +RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i = \ + "systemd-tmpfiles-setup.service" ] || rm -f $i; done); \ + rm -f /lib/systemd/system/multi-user.target.wants/*;\ + rm -f /lib/systemd/system/local-fs.target.wants/*; \ + rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ + rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ + rm -f /lib/systemd/system/anaconda.target.wants/*; + +COPY --from=tomcat /usr/local/tomcat /usr/local/tomcat +COPY --from=tomcat /opt/java /opt/java +COPY instrumentation/setup-tomcat.sh /opt/ +RUN bash /opt/setup-tomcat.sh + +ARG NODE_VERSION=v16 +COPY instrumentation/setup-express.sh /opt +RUN bash /opt/setup-express.sh + +RUN systemctl set-default multi-user.target +ENV init /lib/systemd/systemd + +VOLUME [ "/sys/fs/cgroup" ] + +ENTRYPOINT ["/lib/systemd/systemd"] diff --git a/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.debian-bullseye b/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.debian-bullseye new file mode 100644 index 0000000000..367b459b1e --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.debian-bullseye @@ -0,0 +1,35 @@ +# A debian image with systemd enabled. Must be run with: +# `-d --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro` flags +FROM tomcat:9-jre8 as tomcat + +FROM debian:bullseye + +ENV DEBIAN_FRONTEND noninteractive + +RUN apt-get update &&\ + apt-get install -yq ca-certificates curl procps python3 systemd wget + +ENV container docker +RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i = \ + "systemd-tmpfiles-setup.service" ] || rm -f $i; done); \ + rm -f /lib/systemd/system/multi-user.target.wants/*;\ + rm -f /lib/systemd/system/local-fs.target.wants/*; \ + rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ + rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ + rm -f /lib/systemd/system/anaconda.target.wants/*; + +COPY --from=tomcat /usr/local/tomcat /usr/local/tomcat +COPY --from=tomcat /opt/java /opt/java +COPY instrumentation/setup-tomcat.sh /opt/ +RUN bash /opt/setup-tomcat.sh + +ARG NODE_VERSION=v16 +COPY instrumentation/setup-express.sh /opt +RUN bash /opt/setup-express.sh + +RUN systemctl set-default multi-user.target +ENV init /lib/systemd/systemd + +VOLUME [ "/sys/fs/cgroup" ] + +ENTRYPOINT ["/lib/systemd/systemd"] diff --git a/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.debian-buster b/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.debian-buster new file mode 100644 index 0000000000..d4d955132d --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.debian-buster @@ -0,0 +1,35 @@ +# A debian image with systemd enabled. Must be run with: +# `-d --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro` flags +FROM tomcat:9-jre8 as tomcat + +FROM debian:buster + +ENV DEBIAN_FRONTEND noninteractive + +RUN apt-get update &&\ + apt-get install -yq ca-certificates curl procps python3 systemd wget + +ENV container docker +RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i = \ + "systemd-tmpfiles-setup.service" ] || rm -f $i; done); \ + rm -f /lib/systemd/system/multi-user.target.wants/*;\ + rm -f /lib/systemd/system/local-fs.target.wants/*; \ + rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ + rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ + rm -f /lib/systemd/system/anaconda.target.wants/*; + +COPY --from=tomcat /usr/local/tomcat /usr/local/tomcat +COPY --from=tomcat /opt/java /opt/java +COPY instrumentation/setup-tomcat.sh /opt/ +RUN bash /opt/setup-tomcat.sh + +ARG NODE_VERSION=v16 +COPY instrumentation/setup-express.sh /opt +RUN bash /opt/setup-express.sh + +RUN systemctl set-default multi-user.target +ENV init /lib/systemd/systemd + +VOLUME [ "/sys/fs/cgroup" ] + +ENTRYPOINT ["/lib/systemd/systemd"] diff --git a/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.debian-stretch b/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.debian-stretch new file mode 100644 index 0000000000..b82b32ccea --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.debian-stretch @@ -0,0 +1,38 @@ +# A debian image with systemd enabled. Must be run with: +# `-d --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro` flags +FROM tomcat:9-jre8 as tomcat + +FROM debian:stretch + +ENV DEBIAN_FRONTEND noninteractive + +RUN sed -i 's|http://.*.debian.org|http://archive.debian.org|' /etc/apt/sources.list +RUN sed -i '/stretch-updates/d' /etc/apt/sources.list + +RUN apt-get update &&\ + apt-get install -yq ca-certificates curl procps python3 systemd wget + +ENV container docker +RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i = \ + "systemd-tmpfiles-setup.service" ] || rm -f $i; done); \ + rm -f /lib/systemd/system/multi-user.target.wants/*;\ + rm -f /lib/systemd/system/local-fs.target.wants/*; \ + rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ + rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ + rm -f /lib/systemd/system/anaconda.target.wants/*; + +COPY --from=tomcat /usr/local/tomcat /usr/local/tomcat +COPY --from=tomcat /opt/java /opt/java +COPY instrumentation/setup-tomcat.sh /opt/ +RUN bash /opt/setup-tomcat.sh + +ARG NODE_VERSION=v14 +COPY instrumentation/setup-express.sh /opt +RUN bash /opt/setup-express.sh + +RUN systemctl set-default multi-user.target +ENV init /lib/systemd/systemd + +VOLUME [ "/sys/fs/cgroup" ] + +ENTRYPOINT ["/lib/systemd/systemd"] diff --git a/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.ubuntu-bionic b/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.ubuntu-bionic new file mode 100644 index 0000000000..92f5c124dd --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.ubuntu-bionic @@ -0,0 +1,35 @@ +# A ubuntu image with systemd enabled. Must be run with: +# `-d --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro` flags +FROM tomcat:9-jre8 as tomcat + +FROM ubuntu:bionic + +ENV DEBIAN_FRONTEND noninteractive + +RUN apt-get update &&\ + apt-get install -yq ca-certificates curl procps python3 systemd wget + +ENV container docker +RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i = \ + "systemd-tmpfiles-setup.service" ] || rm -f $i; done); \ + rm -f /lib/systemd/system/multi-user.target.wants/*;\ + rm -f /lib/systemd/system/local-fs.target.wants/*; \ + rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ + rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ + rm -f /lib/systemd/system/anaconda.target.wants/*; + +COPY --from=tomcat /usr/local/tomcat /usr/local/tomcat +COPY --from=tomcat /opt/java /opt/java +COPY instrumentation/setup-tomcat.sh /opt/ +RUN bash /opt/setup-tomcat.sh + +ARG NODE_VERSION=v16 +COPY instrumentation/setup-express.sh /opt +RUN bash /opt/setup-express.sh + +RUN systemctl set-default multi-user.target +ENV init /lib/systemd/systemd + +VOLUME [ "/sys/fs/cgroup" ] + +ENTRYPOINT ["/lib/systemd/systemd"] diff --git a/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.ubuntu-focal b/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.ubuntu-focal new file mode 100644 index 0000000000..875e0ed6d9 --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.ubuntu-focal @@ -0,0 +1,35 @@ +# A ubuntu image with systemd enabled. Must be run with: +# `-d --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro` flags +FROM tomcat:9-jre8 as tomcat + +FROM ubuntu:focal + +ENV DEBIAN_FRONTEND noninteractive + +RUN apt-get update &&\ + apt-get install -yq ca-certificates curl procps python3 systemd wget + +ENV container docker +RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i = \ + "systemd-tmpfiles-setup.service" ] || rm -f $i; done); \ + rm -f /lib/systemd/system/multi-user.target.wants/*;\ + rm -f /lib/systemd/system/local-fs.target.wants/*; \ + rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ + rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ + rm -f /lib/systemd/system/anaconda.target.wants/*; + +COPY --from=tomcat /usr/local/tomcat /usr/local/tomcat +COPY --from=tomcat /opt/java /opt/java +COPY instrumentation/setup-tomcat.sh /opt/ +RUN bash /opt/setup-tomcat.sh + +ARG NODE_VERSION=v16 +COPY instrumentation/setup-express.sh /opt +RUN bash /opt/setup-express.sh + +RUN systemctl set-default multi-user.target +ENV init /lib/systemd/systemd + +VOLUME [ "/sys/fs/cgroup" ] + +ENTRYPOINT ["/lib/systemd/systemd"] diff --git a/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.ubuntu-jammy b/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.ubuntu-jammy new file mode 100644 index 0000000000..a41743666a --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.ubuntu-jammy @@ -0,0 +1,35 @@ +# A ubuntu image with systemd enabled. Must be run with: +# `-d --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro` flags +FROM tomcat:9-jre8 as tomcat + +FROM ubuntu:jammy + +ENV DEBIAN_FRONTEND noninteractive + +RUN apt-get update &&\ + apt-get install -yq ca-certificates curl procps python3 systemd wget + +ENV container docker +RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i = \ + "systemd-tmpfiles-setup.service" ] || rm -f $i; done); \ + rm -f /lib/systemd/system/multi-user.target.wants/*;\ + rm -f /lib/systemd/system/local-fs.target.wants/*; \ + rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ + rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ + rm -f /lib/systemd/system/anaconda.target.wants/*; + +COPY --from=tomcat /usr/local/tomcat /usr/local/tomcat +COPY --from=tomcat /opt/java /opt/java +COPY instrumentation/setup-tomcat.sh /opt/ +RUN bash /opt/setup-tomcat.sh + +ARG NODE_VERSION=v16 +COPY instrumentation/setup-express.sh /opt +RUN bash /opt/setup-express.sh + +RUN systemctl set-default multi-user.target +ENV init /lib/systemd/systemd + +VOLUME [ "/sys/fs/cgroup" ] + +ENTRYPOINT ["/lib/systemd/systemd"] diff --git a/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.ubuntu-xenial b/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.ubuntu-xenial new file mode 100644 index 0000000000..3692ac0886 --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.ubuntu-xenial @@ -0,0 +1,35 @@ +# A ubuntu image with systemd enabled. Must be run with: +# `-d --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro` flags +FROM tomcat:9-jre8 as tomcat + +FROM ubuntu:xenial + +ENV DEBIAN_FRONTEND noninteractive + +RUN apt-get update &&\ + apt-get install -yq ca-certificates curl procps python3 systemd wget + +ENV container docker +RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i = \ + "systemd-tmpfiles-setup.service" ] || rm -f $i; done); \ + rm -f /lib/systemd/system/multi-user.target.wants/*;\ + rm -f /lib/systemd/system/local-fs.target.wants/*; \ + rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ + rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ + rm -f /lib/systemd/system/anaconda.target.wants/*; + +COPY --from=tomcat /usr/local/tomcat /usr/local/tomcat +COPY --from=tomcat /opt/java /opt/java +COPY instrumentation/setup-tomcat.sh /opt/ +RUN bash /opt/setup-tomcat.sh + +ARG NODE_VERSION=v16 +COPY instrumentation/setup-express.sh /opt +RUN bash /opt/setup-express.sh + +RUN systemctl set-default multi-user.target +ENV init /lib/systemd/systemd + +VOLUME [ "/sys/fs/cgroup" ] + +ENTRYPOINT ["/lib/systemd/systemd"] diff --git a/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.amazonlinux-2 b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.amazonlinux-2 new file mode 100644 index 0000000000..ca5c78f4cc --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.amazonlinux-2 @@ -0,0 +1,31 @@ +# A amazonlinux2 image with systemd enabled. Must be run with: +# `-d --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro` flags +FROM tomcat:9-jre8 as tomcat + +FROM amazonlinux:2 + +ENV container docker + +RUN yum install -y curl procps initscripts python3 systemd wget tar + +RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i = \ + "systemd-tmpfiles-setup.service" ] || rm -f $i; done); \ + rm -f /lib/systemd/system/multi-user.target.wants/*;\ + rm -f /lib/systemd/system/local-fs.target.wants/*; \ + rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ + rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ + rm -f /lib/systemd/system/basic.target.wants/*;\ + rm -f /lib/systemd/system/anaconda.target.wants/*; + +COPY --from=tomcat /usr/local/tomcat /usr/local/tomcat +COPY --from=tomcat /opt/java /opt/java +COPY instrumentation/setup-tomcat.sh /opt/ +RUN bash /opt/setup-tomcat.sh + +ARG NODE_VERSION=v16 +COPY instrumentation/setup-express.sh /opt +RUN bash /opt/setup-express.sh + +VOLUME [ "/sys/fs/cgroup" ] + +CMD ["/usr/sbin/init"] diff --git a/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.amazonlinux-2023 b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.amazonlinux-2023 new file mode 100644 index 0000000000..eb83559dd1 --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.amazonlinux-2023 @@ -0,0 +1,31 @@ +# A amazonlinux2023 image with systemd enabled. Must be run with: +# `-d --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro` flags +FROM tomcat:9-jre8 as tomcat + +FROM amazonlinux:2023 + +ENV container docker + +RUN yum install -y procps initscripts python3 systemd systemd-udev wget tar + +RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i = \ + "systemd-tmpfiles-setup.service" ] || rm -f $i; done); \ + rm -f /lib/systemd/system/multi-user.target.wants/*;\ + rm -f /lib/systemd/system/local-fs.target.wants/*; \ + rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ + rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ + rm -f /lib/systemd/system/basic.target.wants/*;\ + rm -f /lib/systemd/system/anaconda.target.wants/*; + +COPY --from=tomcat /usr/local/tomcat /usr/local/tomcat +COPY --from=tomcat /opt/java /opt/java +COPY instrumentation/setup-tomcat.sh /opt/ +RUN bash /opt/setup-tomcat.sh + +ARG NODE_VERSION=v16 +COPY instrumentation/setup-express.sh /opt +RUN bash /opt/setup-express.sh + +VOLUME [ "/sys/fs/cgroup" ] + +CMD ["/usr/sbin/init"] diff --git a/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.centos-7 b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.centos-7 new file mode 100644 index 0000000000..84114fbeab --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.centos-7 @@ -0,0 +1,32 @@ +# A centos7 image with systemd enabled. Must be run with: +# `-d --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro` flags +FROM tomcat:9-jre8 as tomcat + +FROM centos:7 + +ENV container docker + +RUN echo 'fastestmirror=1' >> /etc/yum.conf +RUN yum install -y curl procps initscripts python3 systemd wget + +RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i = \ + "systemd-tmpfiles-setup.service" ] || rm -f $i; done); \ + rm -f /lib/systemd/system/multi-user.target.wants/*;\ + rm -f /lib/systemd/system/local-fs.target.wants/*; \ + rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ + rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ + rm -f /lib/systemd/system/basic.target.wants/*;\ + rm -f /lib/systemd/system/anaconda.target.wants/*; + +COPY --from=tomcat /usr/local/tomcat /usr/local/tomcat +COPY --from=tomcat /opt/java /opt/java +COPY instrumentation/setup-tomcat.sh /opt/ +RUN bash /opt/setup-tomcat.sh + +ARG NODE_VERSION=v14 +COPY instrumentation/setup-express.sh /opt +RUN bash /opt/setup-express.sh + +VOLUME [ "/sys/fs/cgroup" ] + +CMD ["/usr/sbin/init"] diff --git a/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.centos-8 b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.centos-8 new file mode 100644 index 0000000000..e4ab80b670 --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.centos-8 @@ -0,0 +1,32 @@ +# A centos8 image with systemd enabled. Must be run with: +# `-d --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro` flags +FROM tomcat:9-jre8 as tomcat + +FROM quay.io/centos/centos:stream8 + +ENV container docker + +RUN echo 'fastestmirror=1' >> /etc/yum.conf +RUN dnf install -y procps initscripts python3 systemd wget + +RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i = \ + "systemd-tmpfiles-setup.service" ] || rm -f $i; done); \ + rm -f /lib/systemd/system/multi-user.target.wants/*;\ + rm -f /lib/systemd/system/local-fs.target.wants/*; \ + rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ + rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ + rm -f /lib/systemd/system/basic.target.wants/*;\ + rm -f /lib/systemd/system/anaconda.target.wants/*; + +COPY --from=tomcat /usr/local/tomcat /usr/local/tomcat +COPY --from=tomcat /opt/java /opt/java +COPY instrumentation/setup-tomcat.sh /opt/ +RUN bash /opt/setup-tomcat.sh + +ARG NODE_VERSION=v16 +COPY instrumentation/setup-express.sh /opt +RUN bash /opt/setup-express.sh + +VOLUME [ "/sys/fs/cgroup" ] + +CMD ["/usr/sbin/init"] diff --git a/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.centos-9 b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.centos-9 new file mode 100644 index 0000000000..c3c8b794ff --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.centos-9 @@ -0,0 +1,33 @@ +# A centos9 image with systemd enabled. Must be run with: +# `-d --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro` flags +FROM tomcat:9-jre8 as tomcat + +FROM quay.io/centos/centos:stream9 + +ENV container docker + +RUN rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +RUN echo 'fastestmirror=1' >> /etc/yum.conf +RUN dnf install -y procps initscripts python3 systemd wget + +RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i = \ + "systemd-tmpfiles-setup.service" ] || rm -f $i; done); \ + rm -f /lib/systemd/system/multi-user.target.wants/*;\ + rm -f /lib/systemd/system/local-fs.target.wants/*; \ + rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ + rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ + rm -f /lib/systemd/system/basic.target.wants/*;\ + rm -f /lib/systemd/system/anaconda.target.wants/*; + +COPY --from=tomcat /usr/local/tomcat /usr/local/tomcat +COPY --from=tomcat /opt/java /opt/java +COPY instrumentation/setup-tomcat.sh /opt/ +RUN bash /opt/setup-tomcat.sh + +ARG NODE_VERSION=v16 +COPY instrumentation/setup-express.sh /opt +RUN bash /opt/setup-express.sh + +VOLUME [ "/sys/fs/cgroup" ] + +CMD ["/usr/sbin/init"] diff --git a/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.opensuse-12 b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.opensuse-12 new file mode 100644 index 0000000000..99a5c62ee1 --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.opensuse-12 @@ -0,0 +1,33 @@ +# A opensuse12 image with systemd enabled. Must be run with: +# `-d --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro` flags +FROM tomcat:9-jre8 as tomcat + +FROM opensuse/leap:42 + +ENV container docker + +RUN sed -i 's|download.opensuse.org|ftp5.gwdg.de/pub/opensuse/discontinued|' /etc/zypp/repos.d/*.repo +RUN zypper -n clean && zypper -n refresh +RUN zypper -n install -l curl dbus-1 gzip procps python3 systemd-sysvinit tar wget + +RUN (cd /usr/lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i = \ + "systemd-tmpfiles-setup.service" ] || rm -f $i; done); \ + rm -f /usr/lib/systemd/system/multi-user.target.wants/*;\ + rm -f /usr/lib/systemd/system/local-fs.target.wants/*; \ + rm -f /usr/lib/systemd/system/sockets.target.wants/*udev*; \ + rm -f /usr/lib/systemd/system/sockets.target.wants/*initctl*; \ + rm -f /usr/lib/systemd/system/basic.target.wants/*;\ + rm -f /usr/lib/systemd/system/anaconda.target.wants/*; + +COPY --from=tomcat /usr/local/tomcat /usr/local/tomcat +COPY --from=tomcat /opt/java /opt/java +COPY instrumentation/setup-tomcat.sh /opt/ +RUN bash /opt/setup-tomcat.sh + +ARG NODE_VERSION=v16 +COPY instrumentation/setup-express.sh /opt +RUN bash /opt/setup-express.sh + +VOLUME [ "/sys/fs/cgroup" ] + +CMD ["/sbin/init"] diff --git a/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.opensuse-15 b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.opensuse-15 new file mode 100644 index 0000000000..1be395f8a7 --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.opensuse-15 @@ -0,0 +1,31 @@ +# A opensuse15 image with systemd enabled. Must be run with: +# `-d --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro` flags +FROM tomcat:9-jre8 as tomcat + +FROM opensuse/leap:15 + +ENV container docker + +RUN sed -i 's|download.opensuse.org|provo-mirror.opensuse.org|' /etc/zypp/repos.d/*.repo +RUN zypper -n install -l curl dbus-1 gzip python3 systemd-sysvinit tar wget + +RUN (cd /usr/lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i = \ + "systemd-tmpfiles-setup.service" ] || rm -f $i; done); \ + rm -f /usr/lib/systemd/system/multi-user.target.wants/*;\ + rm -f /usr/lib/systemd/system/local-fs.target.wants/*; \ + rm -f /usr/lib/systemd/system/sockets.target.wants/*udev*; \ + rm -f /usr/lib/systemd/system/sockets.target.wants/*initctl*; \ + rm -f /usr/lib/systemd/system/basic.target.wants/*; + +COPY --from=tomcat /usr/local/tomcat /usr/local/tomcat +COPY --from=tomcat /opt/java /opt/java +COPY instrumentation/setup-tomcat.sh /opt/ +RUN bash /opt/setup-tomcat.sh + +ARG NODE_VERSION=v16 +COPY instrumentation/setup-express.sh /opt +RUN bash /opt/setup-express.sh + +VOLUME [ "/sys/fs/cgroup" ] + +CMD ["/sbin/init"] diff --git a/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.oraclelinux-7 b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.oraclelinux-7 new file mode 100644 index 0000000000..cdab8f5e7a --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.oraclelinux-7 @@ -0,0 +1,31 @@ +# A oraclelinux7 image with systemd enabled. Must be run with: +# `-d --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro` flags +FROM tomcat:9-jre8 as tomcat + +FROM oraclelinux:7 + +ENV container docker + +RUN yum install -y curl procps initscripts python3 systemd wget + +RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i = \ + "systemd-tmpfiles-setup.service" ] || rm -f $i; done); \ + rm -f /lib/systemd/system/multi-user.target.wants/*;\ + rm -f /lib/systemd/system/local-fs.target.wants/*; \ + rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ + rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ + rm -f /lib/systemd/system/basic.target.wants/*;\ + rm -f /lib/systemd/system/anaconda.target.wants/*; + +COPY --from=tomcat /usr/local/tomcat /usr/local/tomcat +COPY --from=tomcat /opt/java /opt/java +COPY instrumentation/setup-tomcat.sh /opt/ +RUN bash /opt/setup-tomcat.sh + +ARG NODE_VERSION=v14 +COPY instrumentation/setup-express.sh /opt +RUN bash /opt/setup-express.sh + +VOLUME [ "/sys/fs/cgroup" ] + +CMD ["/usr/sbin/init"] diff --git a/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.oraclelinux-8 b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.oraclelinux-8 new file mode 100644 index 0000000000..ce1010fb37 --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.oraclelinux-8 @@ -0,0 +1,31 @@ +# A oraclelinux8 image with systemd enabled. Must be run with: +# `-d --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro` flags +FROM tomcat:9-jre8 as tomcat + +FROM oraclelinux:8 + +ENV container docker + +RUN dnf install -y curl procps initscripts python3 systemd wget + +RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i = \ + "systemd-tmpfiles-setup.service" ] || rm -f $i; done); \ + rm -f /lib/systemd/system/multi-user.target.wants/*;\ + rm -f /lib/systemd/system/local-fs.target.wants/*; \ + rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ + rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ + rm -f /lib/systemd/system/basic.target.wants/*;\ + rm -f /lib/systemd/system/anaconda.target.wants/*; + +COPY --from=tomcat /usr/local/tomcat /usr/local/tomcat +COPY --from=tomcat /opt/java /opt/java +COPY instrumentation/setup-tomcat.sh /opt/ +RUN bash /opt/setup-tomcat.sh + +ARG NODE_VERSION=v16 +COPY instrumentation/setup-express.sh /opt +RUN bash /opt/setup-express.sh + +VOLUME [ "/sys/fs/cgroup" ] + +CMD ["/usr/sbin/init"] diff --git a/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.oraclelinux-9 b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.oraclelinux-9 new file mode 100644 index 0000000000..cda8cf6ae6 --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.oraclelinux-9 @@ -0,0 +1,31 @@ +# A oraclelinux9 image with systemd enabled. Must be run with: +# `-d --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro` flags +FROM tomcat:9-jre8 as tomcat + +FROM oraclelinux:9 + +ENV container docker + +RUN dnf install -y curl procps initscripts python3 systemd wget + +RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i = \ + "systemd-tmpfiles-setup.service" ] || rm -f $i; done); \ + rm -f /lib/systemd/system/multi-user.target.wants/*;\ + rm -f /lib/systemd/system/local-fs.target.wants/*; \ + rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ + rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ + rm -f /lib/systemd/system/basic.target.wants/*;\ + rm -f /lib/systemd/system/anaconda.target.wants/*; + +COPY --from=tomcat /usr/local/tomcat /usr/local/tomcat +COPY --from=tomcat /opt/java /opt/java +COPY instrumentation/setup-tomcat.sh /opt/ +RUN bash /opt/setup-tomcat.sh + +ARG NODE_VERSION=v16 +COPY instrumentation/setup-express.sh /opt +RUN bash /opt/setup-express.sh + +VOLUME [ "/sys/fs/cgroup" ] + +CMD ["/usr/sbin/init"] diff --git a/internal/buildscripts/packaging/tests/instrumentation/instrumentation_test.py b/internal/buildscripts/packaging/tests/instrumentation/instrumentation_test.py new file mode 100644 index 0000000000..580d7fc486 --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/instrumentation_test.py @@ -0,0 +1,424 @@ +# Copyright Splunk Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import glob +import os +import re +import time + +from pathlib import Path + +import pytest +from iterators import TimeoutIterator + +from tests.helpers.util import ( + copy_file_into_container, + retry, + run_container_cmd, + run_distro_container, + wait_for, + wait_for_container_cmd, + REPO_DIR, + TESTS_DIR, +) + + +IMAGES_DIR = Path(__file__).parent.resolve() / "images" +DEB_DISTROS = [df.split(".")[-1] for df in glob.glob(str(IMAGES_DIR / "deb" / "Dockerfile.*"))] +RPM_DISTROS = [df.split(".")[-1] for df in glob.glob(str(IMAGES_DIR / "rpm" / "Dockerfile.*"))] + +OTELCOL_BIN_DIR = REPO_DIR / "bin" +INSTALLER_PATH = REPO_DIR / "internal" / "buildscripts" / "packaging" / "installer" / "install.sh" +COLLECTOR_CONFIG_PATH = TESTS_DIR / "instrumentation" / "config.yaml" + +PKG_NAME = "splunk-otel-auto-instrumentation" +LIB_DIR = "/usr/lib/splunk-instrumentation" +LIBSPLUNK_PATH = f"{LIB_DIR}/libsplunk.so" +PRELOAD_PATH = "/etc/ld.so.preload" +SYSTEMD_CONF_DIR = "/usr/lib/systemd/system.conf.d" +SAMPLE_SYSTEMD_CONF_PATH = f"{LIB_DIR}/examples/systemd/00-splunk-otel-auto-instrumentation.conf" + +JAVA_AGENT_PATH = f"{LIB_DIR}/splunk-otel-javaagent.jar" +JAVA_CONFIG_PATH = "/etc/splunk/zeroconfig/java.conf" +CUSTOM_JAVA_CONFIG_PATH = TESTS_DIR / "instrumentation" / "libsplunk-java-test.conf" +CUSTOM_JAVA_SYSTEMD_CONF_PATH = TESTS_DIR / "instrumentation" / "systemd-java-test.conf" + +NODE_AGENT_PATH = f"{LIB_DIR}/splunk-otel-js.tgz" +NODE_CONFIG_PATH = "/etc/splunk/zeroconfig/node.conf" +CUSTOM_NODE_CONFIG_PATH = TESTS_DIR / "instrumentation" / "libsplunk-node-test.conf" +CUSTOM_NODE_SYSTEMD_CONF_PATH = TESTS_DIR / "instrumentation" / "systemd-node-test.conf" + +INSTALLED_FILES = [ + JAVA_AGENT_PATH, + NODE_AGENT_PATH, + LIBSPLUNK_PATH, + JAVA_CONFIG_PATH, + NODE_CONFIG_PATH, + SAMPLE_SYSTEMD_CONF_PATH, +] + +TOMCAT_PIDFILE = "/usr/local/tomcat/temp/tomcat.pid" +TOMCAT_ENV = { + "JAVA_HOME": "/opt/java/openjdk", + "CATALINA_PID": TOMCAT_PIDFILE, + "CATALINA_HOME": "/usr/local/tomcat", + "CATALINA_BASE": "/usr/local/tomcat", + "CATALINA_OPTS": "-Xms512M -Xmx1024M -server -XX:+UseParallelGC", + "JAVA_OPTS": "-Djava.awt.headless=true", +} + +EXPRESS_PIDFILE = "/opt/express/express.pid" + + +def get_dockerfile(distro): + if distro in DEB_DISTROS: + return IMAGES_DIR / "deb" / f"Dockerfile.{distro}" + else: + return IMAGES_DIR / "rpm" / f"Dockerfile.{distro}" + + +def get_package(distro, name, arch): + pkg_dir = REPO_DIR / "instrumentation" / "dist" + pkg_paths = [] + if distro in DEB_DISTROS: + pkg_paths = glob.glob(str(pkg_dir / f"{name}*{arch}.deb")) + elif distro in RPM_DISTROS: + if arch == "amd64": + arch = "x86_64" + elif arch == "arm64": + arch = "aarch64" + pkg_paths = glob.glob(str(pkg_dir / f"{name}*{arch}.rpm")) + + if pkg_paths: + return sorted(pkg_paths)[-1] + else: + return None + + +def container_file_exists(container, path): + return container.exec_run(f"test -f {path}").exit_code == 0 + + +def install_package(container, distro, path): + if distro in DEB_DISTROS: + run_container_cmd(container, f"dpkg -i {path}") + else: + run_container_cmd(container, f"rpm -ivh {path}") + + for path in INSTALLED_FILES: + assert container_file_exists(container, path), f"{path} not found" + + +def verify_preload(container, line, exists=True): + code, output = container.exec_run(f"cat {PRELOAD_PATH}") + assert code == 0, f"failed to get contents from {PRELOAD_PATH}" + config = output.decode("utf-8") + + match = re.search(f"^{line}$", config, re.MULTILINE) + + if exists: + assert match, f"'{line}' not found in {PRELOAD_PATH}" + else: + assert not match, f"'{line}' found in {PRELOAD_PATH}" + + +def start_app(container, app, systemd, timeout=300): + if systemd: + print(f"Starting the {app} systemd service ...") + run_container_cmd(container, f"systemctl start {app}") + else: + print(f"Starting {app} from a shell ...") + if app == "tomcat": + run_container_cmd(container, "bash -c /usr/local/tomcat/bin/startup.sh", env=TOMCAT_ENV) + elif app == "express": + run_container_cmd(container, f"bash -l -c 'node /opt/express/app.js & echo $! > {EXPRESS_PIDFILE}'") + + if app == "tomcat": + print("Waiting for http://127.0.0.1:8080/sample ...") + wait_for_container_cmd(container, "curl -sSL http://127.0.0.1:8080/sample", timeout=timeout) + elif app == "express": + print("Waiting for http://127.0.0.1:3000 ...") + wait_for_container_cmd(container, "curl -sSL http://127.0.0.1:3000", timeout=timeout) + + +def stop_app(container, app): + run_container_cmd(container, f"systemctl stop {app}") + + pidfile = TOMCAT_PIDFILE if app == "tomcat" else EXPRESS_PIDFILE + if container_file_exists(container, pidfile): + if app == "tomcat": + run_container_cmd(container, "bash -c /usr/local/tomcat/bin/shutdown.sh", env=TOMCAT_ENV) + elif app == "express": + run_container_cmd(container, f"bash -c 'kill -TERM `cat {pidfile}`'") + run_container_cmd(container, f"rm -f {pidfile}") + + +def verify_attributes(stream, attributes, timeout=300): + found = {} + for key, value in attributes.items(): + found[key] = False if value else True + + start_time = time.time() + for output in TimeoutIterator(stream, timeout=10, sentinel=None): + if output: + output = output.decode("utf-8").rstrip() + print(output) + for key, value in attributes.items(): + if found[key]: + continue + if re.search(f"{key}: {value}", output, re.MULTILINE): + found[key] = True + if False not in found.values() or ((time.time() - start_time) > timeout): + break + + for key, value in attributes.items(): + assert found[key], f"timed out waiting for '{key}: {value}'" + + +def verify_app_instrumentation(container, app, method, attributes, otelcol_path=None): + systemd = True if method == "systemd" else False + + try: + stop_app(container, app) + except AssertionError: + pass + + container.restart() + wait_for_container_cmd(container, "systemctl show-environment", timeout=30) + + if otelcol_path is None: + # start the collector systemd service + run_container_cmd(container, "systemctl start splunk-otel-collector") + wait_for_container_cmd(container, "systemctl status splunk-otel-collector", timeout=30) + # get the output stream for the collector from journald + stream = container.exec_run("journalctl -u splunk-otel-collector -f", stream=True).output + else: + # start the collector from the shell and get the output stream + stream = container.exec_run(f"{otelcol_path} --config=/test/config.yaml", stream=True).output + + start_app(container, app, systemd) + + # check the collector output stream for attributes + verify_attributes(stream, attributes) + + +@pytest.mark.parametrize( + "distro", + [pytest.param(distro, marks=pytest.mark.deb) for distro in DEB_DISTROS] + + [pytest.param(distro, marks=pytest.mark.rpm) for distro in RPM_DISTROS], + ) +@pytest.mark.parametrize("arch", ["amd64", "arm64"]) +def test_tomcat_instrumentation(distro, arch): + if distro == "opensuse-12" and arch == "arm64": + pytest.skip("opensuse-12 arm64 no longer supported") + + otelcol_bin = f"otelcol_linux_{arch}" + otelcol_bin_path = OTELCOL_BIN_DIR / otelcol_bin + assert os.path.isfile(otelcol_bin_path), f"{otelcol_bin_path} not found!" + otelcol = f"/test/{otelcol_bin}" + + pkg_path = get_package(distro, PKG_NAME, arch) + assert pkg_path, f"{PKG_NAME} package not found" + pkg_base = os.path.basename(pkg_path) + + with run_distro_container(distro, dockerfile=get_dockerfile(distro), arch=arch) as container: + copy_file_into_container(container, COLLECTOR_CONFIG_PATH, "/test/config.yaml") + copy_file_into_container(container, pkg_path, f"/test/{pkg_base}") + copy_file_into_container(container, otelcol_bin_path, f"/test/{otelcol_bin}") + run_container_cmd(container, f"chmod a+x /test/{otelcol_bin}") + + install_package(container, distro, f"/test/{pkg_base}") + + for method in ["systemd", "libsplunk"]: + # attributes from default config + attributes = { + r"telemetry\.sdk\.language": r"Str\(java\)", + r"service\.name": r"Str\(Hello, World Application\)", # auto-generated for the sample app + } + + if method == "systemd": + # install the sample drop-in file to enable the agent + run_container_cmd(container, f"mkdir -p {SYSTEMD_CONF_DIR}") + run_container_cmd(container, f"cp -f {SAMPLE_SYSTEMD_CONF_PATH} {SYSTEMD_CONF_DIR}/") + if container_file_exists(container, "/etc/ld.so.preload"): + run_container_cmd(container, "rm -f /etc/ld.so.preload") + else: + # add libsplunk.so to /etc/ld.so.preload + run_container_cmd(container, f"sh -c 'echo {LIBSPLUNK_PATH} > /etc/ld.so.preload'") + + # verify default config + verify_app_instrumentation(container, "tomcat", method, attributes, otelcol_path=otelcol) + + # attributes from custom config + attributes = { + r"telemetry\.sdk\.language": r"Str\(java\)", + r"service\.name": rf"Str\(service_name_from_{method}_java\)", + r"deployment\.environment": rf"Str\(deployment_environment_from_{method}_java\)", + r"com\.splunk\.sourcetype": r"Str\(otel\.profiling\)", + } + + if method == "systemd": + # install the custom drop-in file to configure the agent + copy_file_into_container(container, CUSTOM_JAVA_SYSTEMD_CONF_PATH, f"{SYSTEMD_CONF_DIR}/test.conf") + else: + # overwrite the default libsplunk config with the custom one for testing + copy_file_into_container(container, CUSTOM_JAVA_CONFIG_PATH, JAVA_CONFIG_PATH) + + # verify custom config + verify_app_instrumentation(container, "tomcat", method, attributes, otelcol_path=otelcol) + + +@pytest.mark.parametrize( + "distro", + [pytest.param(distro, marks=pytest.mark.deb) for distro in DEB_DISTROS] + + [pytest.param(distro, marks=pytest.mark.rpm) for distro in RPM_DISTROS], + ) +@pytest.mark.parametrize("arch", ["amd64", "arm64"]) +def test_express_instrumentation(distro, arch): + if distro == "opensuse-12" and arch == "arm64": + pytest.skip("opensuse-12 arm64 no longer supported") + + otelcol_bin = f"otelcol_linux_{arch}" + otelcol_bin_path = OTELCOL_BIN_DIR / otelcol_bin + assert os.path.isfile(otelcol_bin_path), f"{otelcol_bin_path} not found!" + otelcol = f"/test/{otelcol_bin}" + + pkg_path = get_package(distro, PKG_NAME, arch) + assert pkg_path, f"{PKG_NAME} package not found" + pkg_base = os.path.basename(pkg_path) + + # minimum supported node version required for profiling + node_version = 16 + if arch == "arm64" and distro in ("centos-7", "oraclelinux-7"): + # g++ for these distros is too old to install splunk-otel-js with node v16: + # g++: error: unrecognized command line option '-std=gnu++14' + # use the minimum supported node version without profiling instead + node_version = 14 + + buildargs = {"NODE_VERSION": f"v{node_version}"} + + with run_distro_container(distro, dockerfile=get_dockerfile(distro), arch=arch, buildargs=buildargs) as container: + copy_file_into_container(container, COLLECTOR_CONFIG_PATH, "/test/config.yaml") + copy_file_into_container(container, pkg_path, f"/test/{pkg_base}") + copy_file_into_container(container, otelcol_bin_path, otelcol) + run_container_cmd(container, f"chmod a+x /test/{otelcol_bin}") + + install_package(container, distro, f"/test/{pkg_base}") + + if arch == "arm64": + # dev packages and libs required to build splunk-otel-js + if "opensuse" in distro: + run_container_cmd(container, "zypper -n install -t pattern devel_basis") + run_container_cmd(container, "zypper -n install -t pattern devel_C_C++") + elif distro in RPM_DISTROS: + run_container_cmd(container, "yum groupinstall -y 'Development Tools'") + else: + run_container_cmd(container, "apt-get install -y build-essential") + + if distro in ("debian-stretch", "ubuntu-xenial"): + # npm installed with node v16 only supports python 3.6+, but these distros only provide python 3.5 + # downgrade npm to support python 3.5 + run_container_cmd(container, "bash -l -c 'npm install --global npm@^6'") + + # install splunk-otel-js + run_container_cmd(container, f"bash -l -c 'npm install --global {NODE_AGENT_PATH}'") + + for method in ["systemd", "libsplunk"]: + # attributes from default config + attributes = { + r"telemetry\.sdk\.language": r"Str\(nodejs\)", + r"service\.name": r"Str\(unnamed-node-service\)", # auto-generated for the sample app + } + + if method == "systemd": + # install the sample drop-in file to enable the agent + run_container_cmd(container, f"mkdir -p {SYSTEMD_CONF_DIR}") + run_container_cmd(container, f"cp -f {SAMPLE_SYSTEMD_CONF_PATH} {SYSTEMD_CONF_DIR}/") + if container_file_exists(container, "/etc/ld.so.preload"): + run_container_cmd(container, "rm -f /etc/ld.so.preload") + else: + # add libsplunk.so to /etc/ld.so.preload + run_container_cmd(container, f"sh -c 'echo {LIBSPLUNK_PATH} > /etc/ld.so.preload'") + + # verify default config + verify_app_instrumentation(container, "express", method, attributes, otelcol_path=otelcol) + + # attributes from custom config + attributes = { + r"telemetry\.sdk\.language": r"Str\(nodejs\)", + r"service\.name": rf"Str\(service_name_from_{method}_node\)", + r"deployment\.environment": rf"Str\(deployment_environment_from_{method}_node\)", + r"com\.splunk\.sourcetype": None if node_version < 16 else r"Str\(otel\.profiling\)", + } + + if method == "systemd": + # install the custom drop-in file to configure the agent + copy_file_into_container(container, CUSTOM_NODE_SYSTEMD_CONF_PATH, f"{SYSTEMD_CONF_DIR}/test.conf") + else: + # overwrite the default libsplunk config with the custom one for testing + copy_file_into_container(container, CUSTOM_NODE_CONFIG_PATH, NODE_CONFIG_PATH) + + # verify custom config + verify_app_instrumentation(container, "express", method, attributes, otelcol_path=otelcol) + + +@pytest.mark.parametrize( + "distro", + [pytest.param(distro, marks=pytest.mark.deb) for distro in DEB_DISTROS] + + [pytest.param(distro, marks=pytest.mark.rpm) for distro in RPM_DISTROS], + ) +@pytest.mark.parametrize("arch", ["amd64", "arm64"]) +def test_package_uninstall(distro, arch): + if distro == "opensuse-12" and arch == "arm64": + pytest.skip("opensuse-12 arm64 no longer supported") + + pkg_path = get_package(distro, PKG_NAME, arch) + assert pkg_path, f"{PKG_NAME} package not found" + pkg_base = os.path.basename(pkg_path) + + with run_distro_container(distro, dockerfile=get_dockerfile(distro), arch=arch) as container: + copy_file_into_container(container, pkg_path, f"/test/{pkg_base}") + run_container_cmd(container, f"sh -c 'echo \"# This line should be preserved\" >> {PRELOAD_PATH}'") + + # install the package + install_package(container, distro, f"/test/{pkg_base}") + + verify_preload(container, "# This line should be preserved") + + # verify libsplunk.so was not automatically added to /etc/ld.so.preload + verify_preload(container, LIBSPLUNK_PATH, exists=False) + + # explicitly add libsplunk.so to /etc/ld.so.preload + run_container_cmd(container, f"sh -c 'echo {LIBSPLUNK_PATH} >> {PRELOAD_PATH}'") + + # uninstall the package + if distro in DEB_DISTROS: + run_container_cmd(container, f"dpkg -P {PKG_NAME}") + else: + run_container_cmd(container, f"rpm -e {PKG_NAME}") + + # verify the package was uninstalled + if distro in DEB_DISTROS: + assert container.exec_run(f"dpkg -s {PKG_NAME}").exit_code != 0 + else: + assert container.exec_run(f"rpm -q {PKG_NAME}").exit_code != 0 + + # verify files were uninstalled + for path in INSTALLED_FILES: + assert not container_file_exists(container, path) + + # verify libsplunk.so was removed from /etc/ld.so.preload + verify_preload(container, LIBSPLUNK_PATH, exists=False) + + verify_preload(container, "# This line should be preserved") diff --git a/internal/buildscripts/packaging/tests/instrumentation/libsplunk-java-test.conf b/internal/buildscripts/packaging/tests/instrumentation/libsplunk-java-test.conf new file mode 100644 index 0000000000..9c21dca1ef --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/libsplunk-java-test.conf @@ -0,0 +1,6 @@ +JAVA_TOOL_OPTIONS=-javaagent:/usr/lib/splunk-instrumentation/splunk-otel-javaagent.jar +OTEL_RESOURCE_ATTRIBUTES=deployment.environment=deployment_environment_from_libsplunk_java +OTEL_SERVICE_NAME=service_name_from_libsplunk_java +SPLUNK_METRICS_ENABLED=true +SPLUNK_PROFILER_ENABLED=true +SPLUNK_PROFILER_MEMORY_ENABLED=true diff --git a/internal/buildscripts/packaging/tests/instrumentation/libsplunk-node-test.conf b/internal/buildscripts/packaging/tests/instrumentation/libsplunk-node-test.conf new file mode 100644 index 0000000000..b14d37e74c --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/libsplunk-node-test.conf @@ -0,0 +1,6 @@ +NODE_OPTIONS=-r @splunk/otel/instrument +OTEL_RESOURCE_ATTRIBUTES=deployment.environment=deployment_environment_from_libsplunk_node +OTEL_SERVICE_NAME=service_name_from_libsplunk_node +SPLUNK_METRICS_ENABLED=true +SPLUNK_PROFILER_ENABLED=true +SPLUNK_PROFILER_MEMORY_ENABLED=true diff --git a/internal/buildscripts/packaging/tests/instrumentation/setup-express.sh b/internal/buildscripts/packaging/tests/instrumentation/setup-express.sh new file mode 100644 index 0000000000..77d7040118 --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/setup-express.sh @@ -0,0 +1,60 @@ +#!/bin/bash + +set -euo pipefail + +EXPRESS_HOME="/opt/express" +useradd -r -m -U -d $EXPRESS_HOME -s /bin/false express + +NVM_HOME="/opt/nvm" +mkdir -p $NVM_HOME +HOME=$NVM_HOME bash -c 'curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash' +NVM_DIR="$NVM_HOME/.nvm" +[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" + +nvm install --default ${NODE_VERSION:-v16} + +npm config --global set user root + +NODE_PATH="$( npm root -g )" + +mkdir -p /etc/profile.d +echo "export PATH=\$PATH:${NVM_BIN}" >> /etc/profile.d/node.sh +echo "export NODE_PATH=${NODE_PATH}" >> /etc/profile.d/node.sh + +npm install --global express + +cat < ${EXPRESS_HOME}/app.js +var express = require('express'); +var app = express(); + +app.get('/', function (req, res) { + res.send('Hello World'); +}) + +var server = app.listen(3000, function () { + var host = server.address().address + var port = server.address().port + + console.log("Example app listening at http://%s:%s", host, port) +}) +EOH + +chown express:express ${EXPRESS_HOME}/app.js + +mkdir -p /etc/systemd/system +cat < /etc/systemd/system/express.service +[Unit] +After=network.target + +[Service] +Type=simple +User=express +Group=express +Environment=NODE_PATH=${NODE_PATH} +ExecStart=${NVM_BIN}/node ${EXPRESS_HOME}/app.js +ExecStop=/bin/kill -TERM \$MAINPID +Restart=on-failure + +[Install] +WantedBy=multi-user.target +EOH diff --git a/internal/buildscripts/packaging/tests/instrumentation/setup-tomcat.sh b/internal/buildscripts/packaging/tests/instrumentation/setup-tomcat.sh new file mode 100644 index 0000000000..c338d319e0 --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/setup-tomcat.sh @@ -0,0 +1,38 @@ +#!/bin/bash +set -euo pipefail + +TOMCAT_HOME="/usr/local/tomcat" +JAVA_HOME="/opt/java/openjdk" + +wget --no-check-certificate -nv -O ${TOMCAT_HOME}/webapps/sample.war https://tomcat.apache.org/tomcat-9.0-doc/appdev/sample/sample.war + +cat < /etc/systemd/system/tomcat.service +[Unit] +Description=Apache Tomcat Web Application Container +After=network.target + +[Service] +Type=forking + +Environment="JAVA_HOME=${JAVA_HOME}" +Environment="CATALINA_PID=${TOMCAT_HOME}/temp/tomcat.pid" +Environment="CATALINA_HOME=${TOMCAT_HOME}" +Environment="CATALINA_BASE=${TOMCAT_HOME}" +Environment="CATALINA_OPTS=-Xms512M -Xmx1024M -server -XX:+UseParallelGC" +Environment="JAVA_OPTS=-Djava.awt.headless=true" + +ExecStart=${TOMCAT_HOME}/bin/startup.sh +ExecStop=${TOMCAT_HOME}/bin/shutdown.sh + +User=tomcat +Group=tomcat +UMask=0007 +RestartSec=10 +Restart=always + +[Install] +WantedBy=multi-user.target +EOH + +useradd -r -m -U -d $TOMCAT_HOME -s /bin/false tomcat +chown -R tomcat:tomcat $TOMCAT_HOME diff --git a/internal/buildscripts/packaging/tests/instrumentation/systemd-java-test.conf b/internal/buildscripts/packaging/tests/instrumentation/systemd-java-test.conf new file mode 100644 index 0000000000..b5a431265e --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/systemd-java-test.conf @@ -0,0 +1,6 @@ +[Manager] +DefaultEnvironment="OTEL_SERVICE_NAME=service_name_from_systemd_java" +DefaultEnvironment="OTEL_RESOURCE_ATTRIBUTES=deployment.environment=deployment_environment_from_systemd_java" +DefaultEnvironment="SPLUNK_METRICS_ENABLED=true" +DefaultEnvironment="SPLUNK_PROFILER_ENABLED=true" +DefaultEnvironment="SPLUNK_PROFILER_MEMORY_ENABLED=true" diff --git a/internal/buildscripts/packaging/tests/instrumentation/systemd-node-test.conf b/internal/buildscripts/packaging/tests/instrumentation/systemd-node-test.conf new file mode 100644 index 0000000000..32ab46c5e8 --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/systemd-node-test.conf @@ -0,0 +1,6 @@ +[Manager] +DefaultEnvironment="OTEL_SERVICE_NAME=service_name_from_systemd_node" +DefaultEnvironment="OTEL_RESOURCE_ATTRIBUTES=deployment.environment=deployment_environment_from_systemd_node" +DefaultEnvironment="SPLUNK_METRICS_ENABLED=true" +DefaultEnvironment="SPLUNK_PROFILER_ENABLED=true" +DefaultEnvironment="SPLUNK_PROFILER_MEMORY_ENABLED=true" diff --git a/internal/buildscripts/packaging/tests/requirements.txt b/internal/buildscripts/packaging/tests/requirements.txt index fcf77463ac..4fdd8fd3dd 100644 --- a/internal/buildscripts/packaging/tests/requirements.txt +++ b/internal/buildscripts/packaging/tests/requirements.txt @@ -1,4 +1,5 @@ docker==6.1.3 +iterators==0.2.0 psutil==5.9.6 pytest==7.4.2 pytest-html==4.0.2 @@ -6,4 +7,4 @@ pytest-xdist==3.3.1 py>=1.8.2 requests<2.32.0 six==1.16.0 -urllib3<3 \ No newline at end of file +urllib3<3