diff --git a/.github/workflows/documentation-disable-list-audit.yml b/.github/workflows/documentation-synchronization-audit.yml similarity index 52% rename from .github/workflows/documentation-disable-list-audit.yml rename to .github/workflows/documentation-synchronization-audit.yml index fd43443099d0..8a9077e3c1e8 100644 --- a/.github/workflows/documentation-disable-list-audit.yml +++ b/.github/workflows/documentation-synchronization-audit.yml @@ -1,4 +1,4 @@ -name: opentelemetry.io documentation disable list audit +name: Documentation Synchronization Audit (opentelemetry.io) on: schedule: @@ -11,6 +11,8 @@ permissions: jobs: crawl: runs-on: ubuntu-latest + outputs: + audit-output: ${{ steps.audit.outputs.AUDIT_OUTPUT }} steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 @@ -26,7 +28,20 @@ jobs: run: ./gradlew :instrumentation-docs:runAnalysis - name: Run doc site audit - run: ./gradlew :instrumentation-docs:docSiteAudit + id: audit + run: | + if ! output=$(./gradlew :instrumentation-docs:docSiteAudit 2>&1); then + echo "AUDIT_FAILED=true" >> $GITHUB_OUTPUT + echo "AUDIT_OUTPUT<> $GITHUB_OUTPUT + # Extract only the content between our custom markers + echo "$output" | sed -n '/=== AUDIT_FAILURE_START ===/,/=== AUDIT_FAILURE_END ===/p' | \ + sed '/=== AUDIT_FAILURE_START ===/d' | \ + sed '/=== AUDIT_FAILURE_END ===/d' >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + exit 1 + else + echo "AUDIT_FAILED=false" >> $GITHUB_OUTPUT + fi workflow-notification: permissions: @@ -38,3 +53,4 @@ jobs: uses: ./.github/workflows/reusable-workflow-notification.yml with: success: ${{ needs.crawl.result == 'success' }} + failure-details: ${{ needs.crawl.outputs.audit-output }} diff --git a/.github/workflows/reusable-workflow-notification.yml b/.github/workflows/reusable-workflow-notification.yml index 61e8d6267ccb..47bf2207a49b 100644 --- a/.github/workflows/reusable-workflow-notification.yml +++ b/.github/workflows/reusable-workflow-notification.yml @@ -8,6 +8,9 @@ on: success: type: boolean required: true + failure-details: + type: string + required: false permissions: contents: read @@ -31,14 +34,19 @@ jobs: echo $number echo ${{ inputs.success }} + # Prepare the issue body with failure details if available + if [[ -n "${{ inputs.failure-details }}" ]]; then + issue_body="See [$GITHUB_WORKFLOW #$GITHUB_RUN_NUMBER](https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID)."$'\n\n'"## Failure Details"$'\n\n'"${{ inputs.failure-details }}" + else + issue_body="See [$GITHUB_WORKFLOW #$GITHUB_RUN_NUMBER](https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID)." + fi + if [[ $number ]]; then if [[ "${{ inputs.success }}" == "true" ]]; then gh issue close $number else - gh issue comment $number \ - --body "See [$GITHUB_WORKFLOW #$GITHUB_RUN_NUMBER](https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID)." + gh issue comment $number --body "$issue_body" fi elif [[ "${{ inputs.success }}" == "false" ]]; then - gh issue create --title "Workflow failed: $GITHUB_WORKFLOW (#$GITHUB_RUN_NUMBER)" \ - --body "See [$GITHUB_WORKFLOW #$GITHUB_RUN_NUMBER](https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID)." + gh issue create --title "Workflow failed: $GITHUB_WORKFLOW (#$GITHUB_RUN_NUMBER)" --body "$issue_body" fi diff --git a/docs/contributing/documenting-instrumentation.md b/docs/contributing/documenting-instrumentation.md index ce1f7bb4cd5d..01b7acebd582 100644 --- a/docs/contributing/documenting-instrumentation.md +++ b/docs/contributing/documenting-instrumentation.md @@ -227,7 +227,9 @@ All of our instrumentation modules are listed on the opentelemetry.io website in The [Supported Libraries](https://opentelemetry.io/docs/zero-code/java/agent/supported-libraries/) page lists all the library instrumentations that are included in the OpenTelemetry Java agent. It mostly mirrors the information from the [supported libraries](../supported-libraries.md) page in -this repo, and should be updated when adding or removing library instrumentations. +this repo, and should be updated when adding or removing library instrumentations. There is a +[Github action](../../.github/workflows/documentation-synchronization-audit.yml) that runs nightly +to check for any missing instrumentations, and will open an issue if any are found. This page may be automatically generated in the future, but for now it is manually maintained. @@ -238,5 +240,5 @@ page lists the instrumentations in the context of the keys needed for using the `otel.instrumentation.[name].enabled` configuration. All new instrumentations should be added to this list. There is a -[Github action](../../.github/workflows/documentation-disable-list-audit.yml) that runs nightly to check +[Github action](../../.github/workflows/documentation-synchronization-audit.yml) that runs nightly to check for any missing instrumentations, and will open an issue if any are found. diff --git a/instrumentation-docs/src/main/java/io/opentelemetry/instrumentation/docs/DocSynchronization.java b/instrumentation-docs/src/main/java/io/opentelemetry/instrumentation/docs/DocSynchronization.java index 343a614e8c30..af9867b1aed8 100644 --- a/instrumentation-docs/src/main/java/io/opentelemetry/instrumentation/docs/DocSynchronization.java +++ b/instrumentation-docs/src/main/java/io/opentelemetry/instrumentation/docs/DocSynchronization.java @@ -7,190 +7,81 @@ import static java.lang.System.exit; -import io.opentelemetry.instrumentation.docs.utils.FileManager; +import io.opentelemetry.instrumentation.docs.auditors.DocumentationAuditor; +import io.opentelemetry.instrumentation.docs.auditors.SupportedLibrariesAuditor; +import io.opentelemetry.instrumentation.docs.auditors.SuppressionListAuditor; import java.io.IOException; -import java.net.URI; import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; -import java.util.ArrayList; import java.util.Arrays; -import java.util.HashSet; import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.TreeSet; +import java.util.Optional; import java.util.logging.Logger; -import javax.annotation.Nullable; -import org.yaml.snakeyaml.Yaml; /** - * This class is responsible for auditing and synchronizing documentation using the instrumentation - * list yaml. + * This class is responsible for auditing and synchronizing documentation between the source of + * truth (this repo) and the opentelemetry.io site. */ public class DocSynchronization { private static final Logger logger = Logger.getLogger(DocSynchronization.class.getName()); - private static final String DOCUMENTATION_DISABLE_LIST = - "https://raw.githubusercontent.com/open-telemetry/opentelemetry.io/refs/heads/main/content/en/docs/zero-code/java/agent/disable.md"; + private static final List AUDITORS = + List.of(new SuppressionListAuditor(), new SupportedLibrariesAuditor()); - // Used for consolidating instrumentation groups where we override the key with the value - private static final Map INSTRUMENTATION_DISABLE_OVERRIDES = - Map.of("akka-actor-fork-join", "akka-actor"); - - private static final List INSTRUMENTATION_EXCLUSIONS = - List.of("resources", "spring-boot-resources"); - - private DocSynchronization() {} - - /** - * Retrieves contents of the disable page from the main branch of the documentation site. - * - * @return the file content as a string - */ - private static String getDocumentationDisableList(HttpClient client) - throws IOException, InterruptedException { - HttpRequest request = - HttpRequest.newBuilder().uri(URI.create(DOCUMENTATION_DISABLE_LIST)).build(); - - HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); - if (response.statusCode() >= 200 && response.statusCode() < 300) { - return response.body(); - } - throw new IOException("Failed to fetch instrumentation list: " + response); - } - - @SuppressWarnings("unchecked") - public static List parseInstrumentationList(String fileContent) { - List instrumentationList = new ArrayList<>(); - Yaml yaml = new Yaml(); - Map data = yaml.load(fileContent); + public static void main(String[] args) { + HttpClient client = HttpClient.newHttpClient(); - if (data != null && data.get("libraries") instanceof Map) { - Map>> libraries = - (Map>>) data.get("libraries"); - for (List> libraryGroup : libraries.values()) { - for (Map instrumentation : libraryGroup) { - if (instrumentation.get("name") instanceof String) { - instrumentationList.add((String) instrumentation.get("name")); + try { + boolean hasFailures = false; + StringBuilder combinedMessage = new StringBuilder(); + + for (DocumentationAuditor auditor : AUDITORS) { + try { + logger.info("Running " + auditor.getAuditorName() + "..."); + Optional result = auditor.performAudit(client); + + if (result.isPresent()) { + hasFailures = true; + if (!combinedMessage.isEmpty()) { + combinedMessage.append("\n\n"); + } + combinedMessage.append(result.get()); } - } - } - } - return instrumentationList; - } - - /** - * Identifies missing items in the instrumentation list that are not present in the documentation - * disable list. Takes into account any overrides specified in INSTRUMENTATION_DISABLE_OVERRIDES - * and excludes items listed in INSTRUMENTATION_EXCLUSIONS. - * - * @param documentationDisabledList a list of items that are documented - * @param instrumentationList a list of instrumentations from the instrumentation list - * @return a list of missing items that should be documented - */ - public static List identifyMissingItems( - List documentationDisabledList, List instrumentationList) { - Set documentationDisabledSet = new HashSet<>(documentationDisabledList); - - Set sanitizedInstrumentationItems = new TreeSet<>(); - for (String item : instrumentationList) { - sanitizedInstrumentationItems.add(item.replaceFirst("-[0-9].*$", "")); - } - - List missingItems = new ArrayList<>(); - for (String item : sanitizedInstrumentationItems) { - if (INSTRUMENTATION_EXCLUSIONS.contains(item)) { - continue; // Skip excluded items - } - String itemToCheck = INSTRUMENTATION_DISABLE_OVERRIDES.getOrDefault(item, item); - boolean found = false; - for (String disabledItem : documentationDisabledSet) { - if (itemToCheck.startsWith(disabledItem)) { - found = true; - break; - } - } - if (!found) { - missingItems.add(item); - } - } - return missingItems; - } - - /** - * Retrieves the instrumentation list yaml file. - * - * @return a string representation of the instrumentation list - */ - @Nullable - private static String getInstrumentationList() { - // Identify path to repo so we can use absolute paths - String baseRepoPath = System.getProperty("basePath"); - if (baseRepoPath == null) { - baseRepoPath = "./"; - } else { - baseRepoPath += "/"; - } - - String file = baseRepoPath + "docs/instrumentation-list.yaml"; - return FileManager.readFileToString(file); - } - - /** - * Parses the documentation disabled list from the file content and turns it into a list of - * instrumentation names. - * - * @param fileContent the content of the disable.md documentation file - * @return a list of instrumentation names that are documented - */ - public static List parseDocumentationDisabledList(String fileContent) { - List instrumentationList = new ArrayList<>(); - String[] lines = fileContent.split("\\R"); - for (String line : lines) { - if (line.trim().startsWith("|")) { - String[] parts = line.split("\\|"); - if (parts.length > 2) { - String potentialName = parts[2].trim(); - if (potentialName.startsWith("`") && potentialName.endsWith("`")) { - String name = potentialName.substring(1, potentialName.length() - 1); - instrumentationList.add(name); + } catch (IOException | InterruptedException | RuntimeException e) { + logger.severe("Error running " + auditor.getAuditorName() + ": " + e.getMessage()); + hasFailures = true; + if (!combinedMessage.isEmpty()) { + combinedMessage.append("\n\n"); } + combinedMessage + .append("Error in ") + .append(auditor.getAuditorName()) + .append(": ") + .append(e.getMessage()); } } - } - return instrumentationList; - } - public static void main(String[] args) { - HttpClient client = HttpClient.newHttpClient(); - - try { - String content = getDocumentationDisableList(client); - List disabledList = parseDocumentationDisabledList(content); - - String instrumentationListContent = Objects.requireNonNull(getInstrumentationList()); - List instrumentationList = parseInstrumentationList(instrumentationListContent); - - List missingItems = identifyMissingItems(disabledList, instrumentationList); - - if (missingItems.isEmpty()) { - logger.info("No missing items found."); - } else { - StringBuilder sb = new StringBuilder(); - sb.append("Missing Instrumentation List (") - .append(missingItems.size()) - .append(" item(s) missing):\n"); - missingItems.forEach(item -> sb.append(" - ").append(item).append("\n")); - logger.severe(sb.toString()); + if (hasFailures) { + // Add custom markers and "How to Fix" section for GitHub workflow extraction + StringBuilder finalMessage = new StringBuilder(); + finalMessage.append("=== AUDIT_FAILURE_START ===\n"); + finalMessage.append(combinedMessage.toString()); + finalMessage.append("\n\n## How to Fix\n\n"); + finalMessage.append( + "For guidance on updating the OpenTelemetry.io documentation, see: [Documenting Instrumentation](https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/docs/contributing/documenting-instrumentation.md#opentelemetryio)"); + finalMessage.append("\n=== AUDIT_FAILURE_END ==="); + + logger.severe(finalMessage.toString()); exit(1); + } else { + logger.info("All documentation audits passed successfully."); } - } catch (IOException | InterruptedException e) { - logger.severe("Error fetching instrumentation list: " + e.getMessage()); + } catch (RuntimeException e) { + logger.severe("Error running documentation audits: " + e.getMessage()); logger.severe(Arrays.toString(e.getStackTrace())); exit(1); } } + + private DocSynchronization() {} } diff --git a/instrumentation-docs/src/main/java/io/opentelemetry/instrumentation/docs/auditors/DocumentationAuditor.java b/instrumentation-docs/src/main/java/io/opentelemetry/instrumentation/docs/auditors/DocumentationAuditor.java new file mode 100644 index 000000000000..f703397ac186 --- /dev/null +++ b/instrumentation-docs/src/main/java/io/opentelemetry/instrumentation/docs/auditors/DocumentationAuditor.java @@ -0,0 +1,34 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.docs.auditors; + +import java.io.IOException; +import java.net.http.HttpClient; +import java.util.Optional; + +/** + * Base interface for auditing documentation synchronization between the instrumentation repository + * and the OpenTelemetry.io website. + */ +public interface DocumentationAuditor { + + /** + * Performs an audit by comparing local instrumentation data with remote documentation. + * + * @param client HTTP client for making remote requests + * @return Optional.empty() if successful, or Optional.of(errorMessage) if there are issues + * @throws IOException if there's an error fetching remote content + * @throws InterruptedException if the HTTP request is interrupted + */ + Optional performAudit(HttpClient client) throws IOException, InterruptedException; + + /** + * Returns the name of this auditor for logging and reporting purposes. + * + * @return auditor name + */ + String getAuditorName(); +} diff --git a/instrumentation-docs/src/main/java/io/opentelemetry/instrumentation/docs/auditors/SupportedLibrariesAuditor.java b/instrumentation-docs/src/main/java/io/opentelemetry/instrumentation/docs/auditors/SupportedLibrariesAuditor.java new file mode 100644 index 000000000000..ffc6a9d7fafa --- /dev/null +++ b/instrumentation-docs/src/main/java/io/opentelemetry/instrumentation/docs/auditors/SupportedLibrariesAuditor.java @@ -0,0 +1,195 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.docs.auditors; + +import io.opentelemetry.instrumentation.docs.utils.FileManager; +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Optional; +import java.util.Set; +import java.util.TreeSet; + +/** + * Audits the supported libraries list on the OpenTelemetry.io documentation site to ensure it + * matches the local supported-libraries.md file. + */ +public class SupportedLibrariesAuditor implements DocumentationAuditor { + + private static final String REMOTE_SUPPORTED_LIBRARIES_URL = + "https://raw.githubusercontent.com/open-telemetry/opentelemetry.io/refs/heads/main/content/en/docs/zero-code/java/agent/supported-libraries.md"; + + @Override + public Optional performAudit(HttpClient client) throws IOException, InterruptedException { + List localLibraries = parseLocalSupportedLibraries(); + List remoteLibraries = getRemoteSupportedLibraries(client); + List missingItems = identifyMissingItems(remoteLibraries, localLibraries); + + if (missingItems.isEmpty()) { + return Optional.empty(); + } + + StringBuilder sb = new StringBuilder(); + sb.append("Missing Supported Libraries (") + .append(missingItems.size()) + .append(" item(s) missing from remote):\n"); + missingItems.forEach(item -> sb.append(" - ").append(item).append("\n")); + + return Optional.of(sb.toString()); + } + + @Override + public String getAuditorName() { + return "Supported Libraries Auditor"; + } + + /** + * Retrieves and parses the supported libraries from the remote OpenTelemetry.io site. + * + * @param client HTTP client for making requests + * @return list of library names from the remote site + */ + private static List getRemoteSupportedLibraries(HttpClient client) + throws IOException, InterruptedException { + HttpRequest request = + HttpRequest.newBuilder().uri(URI.create(REMOTE_SUPPORTED_LIBRARIES_URL)).build(); + + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); + if (response.statusCode() >= 200 && response.statusCode() < 300) { + return parseLibraryMarkdownTable(response.body()); + } + throw new IOException("Failed to fetch remote supported libraries: " + response); + } + + /** + * Parses the local supported-libraries.md file to extract library names. + * + * @return list of library names from the local file + */ + private static List parseLocalSupportedLibraries() { + String baseRepoPath = System.getProperty("basePath"); + if (baseRepoPath == null) { + baseRepoPath = "./"; + } else { + baseRepoPath += "/"; + } + + String file = baseRepoPath + "docs/supported-libraries.md"; + String fileContent = FileManager.readFileToString(file); + + if (fileContent == null) { + return new ArrayList<>(); + } + + return parseLibraryMarkdownTable(fileContent); + } + + /** + * Parses markdown content to extract library names from the table. + * + * @param content the markdown content + * @return list of library names + */ + private static List parseLibraryMarkdownTable(String content) { + List libraries = new ArrayList<>(); + String[] lines = content.split("\\R"); + + boolean inLibrariesSection = false; + for (String line : lines) { + // Look for the start of the Libraries/Frameworks section (handle both formats) + if (line.contains("## Libraries / Frameworks") + || line.contains("## Libraries and Frameworks")) { + inLibrariesSection = true; + continue; + } + + // Stop when we reach the next major section + if (inLibrariesSection + && line.startsWith("##") + && !line.contains("Libraries / Frameworks") + && !line.contains("Libraries and Frameworks")) { + break; + } + + // Parse table rows in the libraries section + if (inLibrariesSection + && line.trim().startsWith("|") + && !line.contains("Library/Framework") + && !line.contains("----") // Skip separator rows + && !line.trim().equals("|")) { // Skip empty rows + String libraryName = extractLibraryNameFromMarkdownRow(line); + if (!libraryName.isEmpty() && !libraryName.startsWith("-")) { // Skip separator content + libraries.add(libraryName); + } + } + } + + return libraries; + } + + /** + * Extracts the library name from a markdown table row. + * + * @param line the table row line + * @return the library name, or empty string if not found + */ + private static String extractLibraryNameFromMarkdownRow(String line) { + String[] parts = line.split("\\|"); + if (parts.length > 1) { + String firstColumn = parts[1].trim(); + + // Handle markdown links [Text](URL) + if (firstColumn.startsWith("[") && firstColumn.contains("](")) { + int endBracket = firstColumn.indexOf("]("); + return firstColumn.substring(1, endBracket); + } + + return firstColumn; + } + return ""; + } + + /** + * Identifies libraries that are missing from the remote list but present in the local list. + * + * @param remoteLibraries libraries from the remote documentation site + * @param localLibraries libraries from the local supported-libraries.md file + * @return list of missing libraries + */ + private static List identifyMissingItems( + List remoteLibraries, List localLibraries) { + Set remoteSet = new HashSet<>(); + for (String library : remoteLibraries) { + remoteSet.add(normalizeLibraryName(library)); + } + + Set missingItems = new TreeSet<>(); + for (String localLibrary : localLibraries) { + String normalized = normalizeLibraryName(localLibrary); + if (!remoteSet.contains(normalized)) { + missingItems.add(localLibrary); + } + } + + return new ArrayList<>(missingItems); + } + + /** + * Normalizes library names for comparison by removing common variations. + * + * @param libraryName the original library name + * @return normalized library name + */ + private static String normalizeLibraryName(String libraryName) { + return libraryName.trim().toLowerCase(Locale.ROOT).replaceAll("\\s+", " "); + } +} diff --git a/instrumentation-docs/src/main/java/io/opentelemetry/instrumentation/docs/auditors/SuppressionListAuditor.java b/instrumentation-docs/src/main/java/io/opentelemetry/instrumentation/docs/auditors/SuppressionListAuditor.java new file mode 100644 index 000000000000..bf7054c3c5e8 --- /dev/null +++ b/instrumentation-docs/src/main/java/io/opentelemetry/instrumentation/docs/auditors/SuppressionListAuditor.java @@ -0,0 +1,184 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.docs.auditors; + +import io.opentelemetry.instrumentation.docs.utils.FileManager; +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.TreeSet; +import org.yaml.snakeyaml.Yaml; + +/** + * Audits the suppression/disable list on the OpenTelemetry.io documentation site to ensure it + * includes all instrumentations that should be documented. + */ +public class SuppressionListAuditor implements DocumentationAuditor { + + private static final String DOCUMENTATION_DISABLE_LIST = + "https://raw.githubusercontent.com/open-telemetry/opentelemetry.io/refs/heads/main/content/en/docs/zero-code/java/agent/disable.md"; + + // Used for consolidating instrumentation groups where we override the key with the value + private static final Map INSTRUMENTATION_DISABLE_OVERRIDES = + Map.of("akka-actor-fork-join", "akka-actor"); + + private static final List INSTRUMENTATION_EXCLUSIONS = + List.of("resources", "spring-boot-resources"); + + @Override + public Optional performAudit(HttpClient client) throws IOException, InterruptedException { + String instrumentationListContent = getInstrumentationListContent(); + String disableListContent = getDocumentationDisableList(client); + List disabledList = parseDocumentationDisabledList(disableListContent); + List instrumentationList = parseInstrumentationList(instrumentationListContent); + List missingItems = identifyMissingItems(disabledList, instrumentationList); + + if (missingItems.isEmpty()) { + return Optional.empty(); + } + + StringBuilder sb = new StringBuilder(); + sb.append("Missing Disable List (").append(missingItems.size()).append(" item(s) missing):\n"); + missingItems.forEach(item -> sb.append(" - ").append(item).append("\n")); + + return Optional.of(sb.toString()); + } + + @Override + public String getAuditorName() { + return "Suppression List Auditor"; + } + + /** + * Gets the instrumentation list content from the local file. + * + * @return the content of the instrumentation-list.yaml file + * @throws RuntimeException if the file cannot be read + */ + private static String getInstrumentationListContent() { + String baseRepoPath = System.getProperty("basePath"); + if (baseRepoPath == null) { + baseRepoPath = "./"; + } else { + baseRepoPath += "/"; + } + + String file = baseRepoPath + "docs/instrumentation-list.yaml"; + String content = FileManager.readFileToString(file); + if (content == null) { + throw new IllegalStateException("Failed to read instrumentation list from: " + file); + } + return content; + } + + /** + * Retrieves contents of the disable page from the main branch of the documentation site. + * + * @return the file content as a string + */ + private static String getDocumentationDisableList(HttpClient client) + throws IOException, InterruptedException { + HttpRequest request = + HttpRequest.newBuilder().uri(URI.create(DOCUMENTATION_DISABLE_LIST)).build(); + + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); + if (response.statusCode() >= 200 && response.statusCode() < 300) { + return response.body(); + } + throw new IOException("Failed to fetch disable list: " + response); + } + + @SuppressWarnings("unchecked") + public static List parseInstrumentationList(String fileContent) { + List instrumentationList = new ArrayList<>(); + Yaml yaml = new Yaml(); + Map data = yaml.load(fileContent); + + if (data != null && data.get("libraries") instanceof Map) { + Map>> libraries = + (Map>>) data.get("libraries"); + for (List> libraryGroup : libraries.values()) { + for (Map instrumentation : libraryGroup) { + if (instrumentation.get("name") instanceof String) { + instrumentationList.add((String) instrumentation.get("name")); + } + } + } + } + return instrumentationList; + } + + /** + * Identifies missing items in the instrumentation list that are not present in the documentation + * disable list. Takes into account any overrides specified in INSTRUMENTATION_DISABLE_OVERRIDES + * and excludes items listed in INSTRUMENTATION_EXCLUSIONS. + * + * @param documentationDisabledList a list of items that are documented + * @param instrumentationList a list of instrumentations from the instrumentation list + * @return a list of missing items that should be documented + */ + public static List identifyMissingItems( + List documentationDisabledList, List instrumentationList) { + Set documentationDisabledSet = new HashSet<>(documentationDisabledList); + + Set sanitizedInstrumentationItems = new TreeSet<>(); + for (String item : instrumentationList) { + sanitizedInstrumentationItems.add(item.replaceFirst("-[0-9].*$", "")); + } + + List missingItems = new ArrayList<>(); + for (String item : sanitizedInstrumentationItems) { + if (INSTRUMENTATION_EXCLUSIONS.contains(item)) { + continue; // Skip excluded items + } + String itemToCheck = INSTRUMENTATION_DISABLE_OVERRIDES.getOrDefault(item, item); + boolean found = false; + for (String disabledItem : documentationDisabledSet) { + if (itemToCheck.startsWith(disabledItem)) { + found = true; + break; + } + } + if (!found) { + missingItems.add(item); + } + } + return missingItems; + } + + /** + * Parses the documentation disabled list from the file content and turns it into a list of + * instrumentation names. + * + * @param fileContent the content of the disable.md documentation file + * @return a list of instrumentation names that are documented + */ + public static List parseDocumentationDisabledList(String fileContent) { + List instrumentationList = new ArrayList<>(); + String[] lines = fileContent.split("\\R"); + for (String line : lines) { + if (line.trim().startsWith("|")) { + String[] parts = line.split("\\|"); + if (parts.length > 2) { + String potentialName = parts[2].trim(); + if (potentialName.startsWith("`") && potentialName.endsWith("`")) { + String name = potentialName.substring(1, potentialName.length() - 1); + instrumentationList.add(name); + } + } + } + } + return instrumentationList; + } +} diff --git a/instrumentation-docs/src/test/java/io/opentelemetry/instrumentation/docs/DocSynchronizationTest.java b/instrumentation-docs/src/test/java/io/opentelemetry/instrumentation/docs/DocSynchronizationTest.java deleted file mode 100644 index 510c7721e9cc..000000000000 --- a/instrumentation-docs/src/test/java/io/opentelemetry/instrumentation/docs/DocSynchronizationTest.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.instrumentation.docs; - -import static org.assertj.core.api.Assertions.assertThat; - -import java.util.List; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; - -@ExtendWith(MockitoExtension.class) -class DocSynchronizationTest { - - @Test - void testGetDocumentationInstrumentationList() { - String testFile = - """ -## Enable manual instrumentation only - -You can suppress all auto instrumentations but have support for manual -instrumentation with `@WithSpan` and normal API interactions by using -`-Dotel.instrumentation.common.default-enabled=false -Dotel.instrumentation.opentelemetry-api.enabled=true -Dotel.instrumentation.opentelemetry-instrumentation-annotations.enabled=true` - -## Suppressing specific agent instrumentation - -You can suppress agent instrumentation of specific libraries. - -{{% config_option name="otel.instrumentation.[name].enabled" %}} Set to `false` -to suppress agent instrumentation of specific libraries, where [name] is the -corresponding instrumentation name: {{% /config_option %}} - -| Library/Framework | Instrumentation name | -| ------------------------------------------------ | ------------------------------------------- | -| Additional methods tracing | `methods` | -| Additional tracing annotations | `external-annotations` | -| Akka Actor | `akka-actor` | -| Akka HTTP | `akka-http` | -| Apache Axis2 | `axis2` | -| Apache Camel | `camel` | -"""; - - List result = DocSynchronization.parseDocumentationDisabledList(testFile); - assertThat(result.size()).isEqualTo(6); - assertThat(result) - .containsExactlyInAnyOrder( - "methods", "external-annotations", "akka-actor", "akka-http", "axis2", "camel"); - } - - @Test - void testParseInstrumentationList() { - String testList = - """ -libraries: - activej: - - name: activej-http-6.0 - description: This instrumentation enables SERVER spans and metrics for the ActiveJ - HTTP server. - source_path: instrumentation/activej-http-6.0 - minimum_java_version: 17 - scope: - name: io.opentelemetry.activej-http-6.0 - target_versions: - javaagent: - - io.activej:activej-http:[6.0,) - telemetry: - - when: default - metrics: - - name: http.server.request.duration - description: Duration of HTTP server requests. - type: HISTOGRAM - unit: s - attributes: - - name: http.request.method - type: STRING - - name: http.response.status_code - type: LONG - - name: network.protocol.version - type: STRING - - name: url.scheme - type: STRING - akka: - - name: akka-actor-2.3 - source_path: instrumentation/akka/akka-actor-2.3 - scope: - name: io.opentelemetry.akka-actor-2.3 - target_versions: - javaagent: - - com.typesafe.akka:akka-actor_2.11:[2.3,) - - com.typesafe.akka:akka-actor_2.12:[2.3,) - - com.typesafe.akka:akka-actor_2.13:[2.3,) - - name: akka-actor-fork-join-2.5 - source_path: instrumentation/akka/akka-actor-fork-join-2.5 - scope: - name: io.opentelemetry.akka-actor-fork-join-2.5 - target_versions: - javaagent: - - com.typesafe.akka:akka-actor_2.12:[2.5,2.6) - - com.typesafe.akka:akka-actor_2.13:[2.5.23,2.6) - - com.typesafe.akka:akka-actor_2.11:[2.5,) - - name: akka-http-10.0 - description: This instrumentation enables CLIENT and SERVER spans and metrics - for the Akka HTTP client and server. - source_path: instrumentation/akka/akka-http-10.0 - scope: - name: io.opentelemetry.akka-http-10.0 -"""; - List result = DocSynchronization.parseInstrumentationList(testList); - - assertThat(result.size()).isEqualTo(4); - assertThat(result) - .containsExactlyInAnyOrder( - "activej-http-6.0", "akka-actor-2.3", "akka-actor-fork-join-2.5", "akka-http-10.0"); - } - - @Test - void identifyMissingItems() { - List documentationDisabledList = List.of("methods", "akka-actor", "akka-http"); - - List instrumentationList = - List.of( - "methods", - "akka-actor-2.3", - "activej-http-6.0", - "akka-actor-fork-join-2.5", - "camel-2.20"); - - List missingItems = - DocSynchronization.identifyMissingItems(documentationDisabledList, instrumentationList); - assertThat(missingItems.size()).isEqualTo(2); - assertThat(missingItems).containsExactlyInAnyOrder("camel", "activej-http"); - } - - @Test - void testIdentifyMissingItemsWithHyphenatedMatch() { - List documentationDisabledList = List.of("clickhouse"); - List instrumentationList = List.of("clickhouse-client-0.5"); - - List missingItems = - DocSynchronization.identifyMissingItems(documentationDisabledList, instrumentationList); - assertThat(missingItems).isEmpty(); - } -} diff --git a/instrumentation-docs/src/test/java/io/opentelemetry/instrumentation/docs/auditors/SupportedLibrariesAuditorTest.java b/instrumentation-docs/src/test/java/io/opentelemetry/instrumentation/docs/auditors/SupportedLibrariesAuditorTest.java new file mode 100644 index 000000000000..d344b39b5e96 --- /dev/null +++ b/instrumentation-docs/src/test/java/io/opentelemetry/instrumentation/docs/auditors/SupportedLibrariesAuditorTest.java @@ -0,0 +1,169 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.docs.auditors; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import io.opentelemetry.instrumentation.docs.utils.FileManager; +import java.io.IOException; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.Optional; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +@SuppressWarnings("unchecked") +class SupportedLibrariesAuditorTest { + + @Test + void testPerformAuditWithNoMissingItems() throws IOException, InterruptedException { + HttpClient mockClient = mock(HttpClient.class); + HttpResponse mockResponse = mock(HttpResponse.class); + when(mockClient.send(any(HttpRequest.class), eq(HttpResponse.BodyHandlers.ofString()))) + .thenReturn(mockResponse); + when(mockResponse.statusCode()).thenReturn(200); + when(mockResponse.body()).thenReturn(createRemoteSupportedLibrariesContent()); + + try (MockedStatic fileManagerMock = Mockito.mockStatic(FileManager.class)) { + fileManagerMock + .when(() -> FileManager.readFileToString(any())) + .thenReturn(createLocalSupportedLibrariesContent()); + + SupportedLibrariesAuditor auditor = new SupportedLibrariesAuditor(); + Optional result = auditor.performAudit(mockClient); + + assertThat(result).isEmpty(); + } + } + + @Test + void testPerformAuditWithMissingItems() throws IOException, InterruptedException { + HttpClient mockClient = mock(HttpClient.class); + HttpResponse mockResponse = mock(HttpResponse.class); + when(mockClient.send(any(HttpRequest.class), eq(HttpResponse.BodyHandlers.ofString()))) + .thenReturn(mockResponse); + when(mockResponse.statusCode()).thenReturn(200); + when(mockResponse.body()).thenReturn(createRemoteSupportedLibrariesContentMissing()); + + try (MockedStatic fileManagerMock = Mockito.mockStatic(FileManager.class)) { + fileManagerMock + .when(() -> FileManager.readFileToString(any())) + .thenReturn(createLocalSupportedLibrariesContent()); + + SupportedLibrariesAuditor auditor = new SupportedLibrariesAuditor(); + Optional result = auditor.performAudit(mockClient); + + assertThat(result).isPresent(); + assertThat(result.get()) + .contains("Missing Supported Libraries (1 item(s) missing from remote):"); + assertThat(result.get()).contains("- Apache Camel"); + } + } + + private static String createLocalSupportedLibrariesContent() { + return """ +# Supported libraries, frameworks, application servers, and JVMs + +We automatically instrument and support a huge number of libraries, frameworks, +and application servers... right out of the box! + +## Contents + +- [Libraries / Frameworks](#libraries--frameworks) +- [Application Servers](#application-servers) + +## Libraries / Frameworks + +These are the supported libraries and frameworks: + +| Library/Framework | Auto-instrumented versions | Standalone Library Instrumentation [1] | Semantic Conventions | +|---------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------| +| [ActiveJ](https://activej.io/) | 6.0+ | N/A | [HTTP Server Spans], [HTTP Server Metrics] | +| [Akka Actors](https://doc.akka.io/docs/akka/current/typed/index.html) | 2.3+ | N/A | Context propagation | +| [Apache Camel](https://camel.apache.org/) | 2.20+ (not including 3.0+ yet) | N/A | Dependent on components in use | + +## Application Servers + +These are the application servers that the smoke tests are run against: + +| Application server | Version | JVM | OS | +|---------------------------------------------------------------------------------------|------------------------------------------|--------------------------------------------------------|---------------------------------------| +| [Jetty](https://www.eclipse.org/jetty/) | 9.4.53 | OpenJDK 8, 11, 17, 21, 23
OpenJ9 8, 11, 17, 21, 23 | [`ubuntu-latest`], [`windows-latest`] | +"""; + } + + private static String createRemoteSupportedLibrariesContent() { + return """ +# Supported libraries, frameworks, application servers, and JVMs + +We automatically instrument and support a huge number of libraries, frameworks, +and application servers... right out of the box! + +## Contents + +- [Libraries / Frameworks](#libraries--frameworks) +- [Application Servers](#application-servers) + +## Libraries / Frameworks + +These are the supported libraries and frameworks: + +| Library/Framework | Auto-instrumented versions | Standalone Library Instrumentation [1] | Semantic Conventions | +|---------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------| +| [ActiveJ](https://activej.io/) | 6.0+ | N/A | [HTTP Server Spans], [HTTP Server Metrics] | +| [Akka Actors](https://doc.akka.io/docs/akka/current/typed/index.html) | 2.3+ | N/A | Context propagation | +| [Apache Camel](https://camel.apache.org/) | 2.20+ (not including 3.0+ yet) | N/A | Dependent on components in use | + +## Application Servers + +These are the application servers that the smoke tests are run against: + +| Application server | Version | JVM | OS | +|---------------------------------------------------------------------------------------|------------------------------------------|--------------------------------------------------------|---------------------------------------| +| [Jetty](https://www.eclipse.org/jetty/) | 9.4.53 | OpenJDK 8, 11, 17, 21, 23
OpenJ9 8, 11, 17, 21, 23 | [`ubuntu-latest`], [`windows-latest`] | +"""; + } + + private static String createRemoteSupportedLibrariesContentMissing() { + return """ +# Supported libraries, frameworks, application servers, and JVMs + +We automatically instrument and support a huge number of libraries, frameworks, +and application servers... right out of the box! + +## Contents + +- [Libraries / Frameworks](#libraries--frameworks) +- [Application Servers](#application-servers) + +## Libraries / Frameworks + +These are the supported libraries and frameworks: + +| Library/Framework | Auto-instrumented versions | Standalone Library Instrumentation [1] | Semantic Conventions | +|---------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------| +| [ActiveJ](https://activej.io/) | 6.0+ | N/A | [HTTP Server Spans], [HTTP Server Metrics] | +| [Akka Actors](https://doc.akka.io/docs/akka/current/typed/index.html) | 2.3+ | N/A | Context propagation | + +## Application Servers + +These are the application servers that the smoke tests are run against: + +| Application server | Version | JVM | OS | +|---------------------------------------------------------------------------------------|------------------------------------------|--------------------------------------------------------|---------------------------------------| +| [Jetty](https://www.eclipse.org/jetty/) | 9.4.53 | OpenJDK 8, 11, 17, 21, 23
OpenJ9 8, 11, 17, 21, 23 | [`ubuntu-latest`], [`windows-latest`] | +"""; + } +} diff --git a/instrumentation-docs/src/test/java/io/opentelemetry/instrumentation/docs/auditors/SuppressionListAuditorTest.java b/instrumentation-docs/src/test/java/io/opentelemetry/instrumentation/docs/auditors/SuppressionListAuditorTest.java new file mode 100644 index 000000000000..cc73bc6d2584 --- /dev/null +++ b/instrumentation-docs/src/test/java/io/opentelemetry/instrumentation/docs/auditors/SuppressionListAuditorTest.java @@ -0,0 +1,274 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.docs.auditors; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import io.opentelemetry.instrumentation.docs.utils.FileManager; +import java.io.IOException; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +@SuppressWarnings("unchecked") +class SuppressionListAuditorTest { + + @Test + void testPerformAuditWithNoMissingItems() throws IOException, InterruptedException { + HttpClient mockClient = mock(HttpClient.class); + HttpResponse mockResponse = mock(HttpResponse.class); + when(mockClient.send(any(HttpRequest.class), eq(HttpResponse.BodyHandlers.ofString()))) + .thenReturn(mockResponse); + when(mockResponse.statusCode()).thenReturn(200); + when(mockResponse.body()).thenReturn(createDisableListContent()); + + try (MockedStatic fileManagerMock = Mockito.mockStatic(FileManager.class)) { + fileManagerMock + .when(() -> FileManager.readFileToString(any())) + .thenReturn(createInstrumentationListContent()); + + SuppressionListAuditor auditor = new SuppressionListAuditor(); + Optional result = auditor.performAudit(mockClient); + + assertThat(result).isEmpty(); + } + } + + @Test + void testPerformAuditWithMissingItems() throws IOException, InterruptedException { + HttpClient mockClient = mock(HttpClient.class); + HttpResponse mockResponse = mock(HttpResponse.class); + when(mockClient.send(any(HttpRequest.class), eq(HttpResponse.BodyHandlers.ofString()))) + .thenReturn(mockResponse); + when(mockResponse.statusCode()).thenReturn(200); + when(mockResponse.body()).thenReturn(createDisableListContentMissing()); + + try (MockedStatic fileManagerMock = Mockito.mockStatic(FileManager.class)) { + fileManagerMock + .when(() -> FileManager.readFileToString(any())) + .thenReturn(createInstrumentationListContent()); + + SuppressionListAuditor auditor = new SuppressionListAuditor(); + Optional result = auditor.performAudit(mockClient); + + assertThat(result).isPresent(); + assertThat(result.get()).contains("Missing Disable List (1 item(s) missing):"); + assertThat(result.get()).contains("- activej-http"); + } + } + + @Test + void testGetAuditorName() { + SuppressionListAuditor auditor = new SuppressionListAuditor(); + assertThat(auditor.getAuditorName()).isEqualTo("Suppression List Auditor"); + } + + @Test + void testParseDocumentationDisabledList() { + String testFile = + """ +## Enable manual instrumentation only + +You can suppress all auto instrumentations but have support for manual +instrumentation with `@WithSpan` and normal API interactions by using +`-Dotel.instrumentation.common.default-enabled=false -Dotel.instrumentation.opentelemetry-api.enabled=true -Dotel.instrumentation.opentelemetry-instrumentation-annotations.enabled=true` + +## Suppressing specific agent instrumentation + +You can suppress agent instrumentation of specific libraries. + +{{% config_option name="otel.instrumentation.[name].enabled" %}} Set to `false` +to suppress agent instrumentation of specific libraries, where [name] is the +corresponding instrumentation name: {{% /config_option %}} + +| Library/Framework | Instrumentation name | +| ------------------------------------------------ | ------------------------------------------- | +| Additional methods tracing | `methods` | +| Additional tracing annotations | `external-annotations` | +| Akka Actor | `akka-actor` | +| Akka HTTP | `akka-http` | +| Apache Axis2 | `axis2` | +| Apache Camel | `camel` | +"""; + + var result = SuppressionListAuditor.parseDocumentationDisabledList(testFile); + assertThat(result).hasSize(6); + assertThat(result) + .containsExactlyInAnyOrder( + "methods", "external-annotations", "akka-actor", "akka-http", "axis2", "camel"); + } + + @Test + void testParseInstrumentationList() { + String testList = + """ +libraries: + activej: + - name: activej-http-6.0 + description: This instrumentation enables SERVER spans and metrics for the ActiveJ + HTTP server. + source_path: instrumentation/activej-http-6.0 + minimum_java_version: 17 + scope: + name: io.opentelemetry.activej-http-6.0 + target_versions: + javaagent: + - io.activej:activej-http:[6.0,) + akka: + - name: akka-actor-2.3 + source_path: instrumentation/akka/akka-actor-2.3 + scope: + name: io.opentelemetry.akka-actor-2.3 + target_versions: + javaagent: + - com.typesafe.akka:akka-actor_2.11:[2.3,) + - com.typesafe.akka:akka-actor_2.12:[2.3,) + - com.typesafe.akka:akka-actor_2.13:[2.3,) + - name: akka-actor-fork-join-2.5 + source_path: instrumentation/akka/akka-actor-fork-join-2.5 + scope: + name: io.opentelemetry.akka-actor-fork-join-2.5 + target_versions: + javaagent: + - com.typesafe.akka:akka-actor_2.12:[2.5,2.6) + - com.typesafe.akka:akka-actor_2.13:[2.5.23,2.6) + - com.typesafe.akka:akka-actor_2.11:[2.5,) + - name: akka-http-10.0 + description: This instrumentation enables CLIENT and SERVER spans and metrics + for the Akka HTTP client and server. + source_path: instrumentation/akka/akka-http-10.0 + scope: + name: io.opentelemetry.akka-http-10.0 +"""; + var result = SuppressionListAuditor.parseInstrumentationList(testList); + + assertThat(result).hasSize(4); + assertThat(result) + .containsExactlyInAnyOrder( + "activej-http-6.0", "akka-actor-2.3", "akka-actor-fork-join-2.5", "akka-http-10.0"); + } + + @Test + void testIdentifyMissingItems() { + var documentationDisabledList = List.of("methods", "akka-actor", "akka-http"); + var instrumentationList = + List.of( + "methods", + "akka-actor-2.3", + "activej-http-6.0", + "akka-actor-fork-join-2.5", + "camel-2.20"); + + var missingItems = + SuppressionListAuditor.identifyMissingItems(documentationDisabledList, instrumentationList); + assertThat(missingItems).hasSize(2); + assertThat(missingItems).containsExactlyInAnyOrder("camel", "activej-http"); + } + + @Test + void testIdentifyMissingItemsWithHyphenatedMatch() { + var documentationDisabledList = List.of("clickhouse"); + var instrumentationList = List.of("clickhouse-client-0.5"); + + var missingItems = + SuppressionListAuditor.identifyMissingItems(documentationDisabledList, instrumentationList); + assertThat(missingItems).isEmpty(); + } + + private static String createDisableListContent() { + return """ +## Enable manual instrumentation only + +You can suppress all auto instrumentations but have support for manual +instrumentation with `@WithSpan` and normal API interactions by using +`-Dotel.instrumentation.common.default-enabled=false -Dotel.instrumentation.opentelemetry-api.enabled=true -Dotel.instrumentation.opentelemetry-instrumentation-annotations.enabled=true` + +## Suppressing specific agent instrumentation + +You can suppress agent instrumentation of specific libraries. + +{{% config_option name="otel.instrumentation.[name].enabled" %}} Set to `false` +to suppress agent instrumentation of specific libraries, where [name] is the +corresponding instrumentation name: {{% /config_option %}} + +| Library/Framework | Instrumentation name | +| ------------------------------------------------ | ------------------------------------------- | +| Additional methods tracing | `methods` | +| ActiveJ | `activej-http` | +| Akka Actor | `akka-actor` | +| Akka HTTP | `akka-http` | +"""; + } + + private static String createDisableListContentMissing() { + return """ +## Enable manual instrumentation only + +You can suppress all auto instrumentations but have support for manual +instrumentation with `@WithSpan` and normal API interactions by using +`-Dotel.instrumentation.common.default-enabled=false -Dotel.instrumentation.opentelemetry-api.enabled=true -Dotel.instrumentation.opentelemetry-instrumentation-annotations.enabled=true` + +## Suppressing specific agent instrumentation + +You can suppress agent instrumentation of specific libraries. + +{{% config_option name="otel.instrumentation.[name].enabled" %}} Set to `false` +to suppress agent instrumentation of specific libraries, where [name] is the +corresponding instrumentation name: {{% /config_option %}} + +| Library/Framework | Instrumentation name | +| ------------------------------------------------ | ------------------------------------------- | +| Additional methods tracing | `methods` | +| Akka Actor | `akka-actor` | +| Akka HTTP | `akka-http` | +"""; + } + + private static String createInstrumentationListContent() { + return """ +libraries: + activej: + - name: activej-http-6.0 + description: This instrumentation enables SERVER spans and metrics for the ActiveJ + HTTP server. + source_path: instrumentation/activej-http-6.0 + minimum_java_version: 17 + scope: + name: io.opentelemetry.activej-http-6.0 + target_versions: + javaagent: + - io.activej:activej-http:[6.0,) + akka: + - name: akka-actor-2.3 + source_path: instrumentation/akka/akka-actor-2.3 + scope: + name: io.opentelemetry.akka-actor-2.3 + target_versions: + javaagent: + - com.typesafe.akka:akka-actor_2.11:[2.3,) + - com.typesafe.akka:akka-actor_2.12:[2.3,) + - com.typesafe.akka:akka-actor_2.13:[2.3,) + - name: akka-http-10.0 + description: This instrumentation enables CLIENT and SERVER spans and metrics + for the Akka HTTP client and server. + source_path: instrumentation/akka/akka-http-10.0 + scope: + name: io.opentelemetry.akka-http-10.0 +"""; + } +}