Profiling requires that the async-profiler shared library is exported to a temporary location and loaded by the JVM. This can fail due to /tmp partition restrictions or missing system libraries.

Symptoms

You may see errors similar to:

ERROR com.atatus.apm.agent.profiler.SamplingProfiler - Stopping profiler
java.lang.IllegalStateException: It is likely that /tmp is not an executable location. Consider setting the profiling_inferred_spans_lib_directory property to a directory in a partition that allows execution
    at com.atatus.apm.agent.profiler.asyncprofiler.AsyncProfiler.getInstance(AsyncProfiler.java:86)
    ...
Caused by: java.lang.UnsatisfiedLinkError: /tmp/libasyncProfiler-linux-x64-xxx.so: Error loading shared library libstdc++.so.6: No such file or directory (needed by /tmp/libasyncProfiler-linux-x64-xxx.so)

This typically happens when: - The /tmp partition is mounted with noexec flag - Security policies prevent execution from temporary directories - Container environments with restricted /tmp permissions - The libstdc++ library is missing in the Docker/container image

Solution

Fix 1: Non-executable /tmp partition

If /tmp is not executable, set the trace_spans_lib_directory property to an alternative directory that allows execution (e.g., /opt/atatus).

Step 1: Create the directory and set permissions

The directory must exist and be executable before the application starts.

copy
icon/buttons/copy
# Create the directory
mkdir -p /opt/atatus

# Set executable permissions
chmod 755 /opt/atatus

For Docker images, add this to your Dockerfile:

copy
icon/buttons/copy
RUN mkdir -p /opt/atatus && chmod 755 /opt/atatus

Step 2: Configure the agent

copy
icon/buttons/copy
// Java System Properties
-Datatus.trace_spans_lib_directory=/opt/atatus

// Environment Variable
export ATATUS_TRACE_SPANS_LIB_DIRECTORY=/opt/atatus

If unset, the value of the java.io.tmpdir system property will be used.


Fix 2: Missing libstdc++ on Alpine Linux

If you are using an Alpine-based Docker image (e.g., eclipse-temurin:17-jre-alpine), the error may occur because Alpine uses musl libc instead of glibc. The async-profiler requires libstdc++ which is not included by default in Alpine.

The key indicator is this error message:

Error loading shared library libstdc++.so.6: No such file or directory

Install the required libraries by adding this to your Dockerfile:

copy
icon/buttons/copy
RUN apk add --no-cache libstdc++ gcompat
  • libstdc++ – Required by the async-profiler
  • gcompat – glibc compatibility layer for Alpine

Example Dockerfile:

copy
icon/buttons/copy
FROM eclipse-temurin:17-jre-alpine

RUN apk add --no-cache libstdc++ gcompat

WORKDIR /app
COPY target/*.jar app.jar
COPY atatus-java-agent.jar .

RUN mkdir -p /opt/atatus

ENTRYPOINT ["java", \
  "-javaagent:./atatus-java-agent.jar", \
  "-Datatus.license_key=lic_apm_xxx", \
  "-Datatus.app_name=your-app-name", \
  "-Datatus.trace_spans_lib_directory=/opt/atatus", \
  "-jar", "app.jar" \
]

Alternative: If you want to avoid native library issues entirely, use a glibc-based image like eclipse-temurin:17-jre-jammy instead of Alpine.

Configuration Reference

Property Value
Default <none>
Type String
Dynamic false
Java System Properties atatus.trace_spans_lib_directory
Property file trace_spans_lib_directory
Environment ATATUS_TRACE_SPANS_LIB_DIRECTORY