Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions instrumentation-docs/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ tasks {
val runAnalysis by registering(JavaExec::class) {
dependsOn(classes)

systemProperty("basePath", project.rootDir)
mainClass.set("io.opentelemetry.instrumentation.docs.DocGeneratorApplication")
classpath(sourceSets["main"].runtimeClasspath)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

import static java.util.Locale.Category.FORMAT;

import com.fasterxml.jackson.core.JsonProcessingException;
import io.opentelemetry.instrumentation.docs.internal.InstrumentationModule;
import io.opentelemetry.instrumentation.docs.utils.FileManager;
import io.opentelemetry.instrumentation.docs.utils.YamlHelper;
Expand All @@ -26,20 +25,26 @@ public class DocGeneratorApplication {

private static final Logger logger = Logger.getLogger(DocGeneratorApplication.class.getName());

public static void main(String[] args) throws JsonProcessingException {
FileManager fileManager = new FileManager("instrumentation/");
public static void main(String[] args) throws IOException {
// Identify path to repo so we can use absolute paths
String baseRepoPath = System.getProperty("basePath");
if (baseRepoPath == null) {
baseRepoPath = "./";
} else {
baseRepoPath += "/";
}

FileManager fileManager = new FileManager(baseRepoPath);
List<InstrumentationModule> modules = new InstrumentationAnalyzer(fileManager).analyze();

try (BufferedWriter writer =
Files.newBufferedWriter(
Paths.get("docs/instrumentation-list.yaml"), Charset.defaultCharset())) {
Paths.get(baseRepoPath + "docs/instrumentation-list.yaml"), Charset.defaultCharset())) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You really don't need to specify the charset. By default newBufferedWriter uses utf-8 which is what you want. Default charset could be something else.

writer.write("# This file is generated and should not be manually edited.\n");
writer.write("# The structure and contents are a work in progress and subject to change.\n");
writer.write(
"# For more information see: https://github.com/open-telemetry/opentelemetry-java-instrumentation/issues/13468\n\n");
YamlHelper.generateInstrumentationYaml(modules, writer);
} catch (IOException e) {
logger.severe("Error writing instrumentation list: " + e.getMessage());
}

printStats(modules);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,16 @@

import static io.opentelemetry.instrumentation.docs.parsers.GradleParser.parseGradleFile;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.exc.ValueInstantiationException;
import io.opentelemetry.instrumentation.docs.internal.DependencyInfo;
import io.opentelemetry.instrumentation.docs.internal.EmittedMetrics;
import io.opentelemetry.instrumentation.docs.internal.InstrumentationModule;
import io.opentelemetry.instrumentation.docs.internal.InstrumentationType;
import io.opentelemetry.instrumentation.docs.parsers.MetricParser;
import io.opentelemetry.instrumentation.docs.utils.FileManager;
import io.opentelemetry.instrumentation.docs.utils.InstrumentationPath;
import io.opentelemetry.instrumentation.docs.utils.YamlHelper;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
Expand All @@ -41,7 +42,7 @@ class InstrumentationAnalyzer {
* @return a list of {@link InstrumentationModule} objects with aggregated types
*/
public static List<InstrumentationModule> convertToInstrumentationModules(
List<InstrumentationPath> paths) {
String rootPath, List<InstrumentationPath> paths) {
Map<String, InstrumentationModule> moduleMap = new HashMap<>();

for (InstrumentationPath path : paths) {
Expand All @@ -50,7 +51,7 @@ public static List<InstrumentationModule> convertToInstrumentationModules(
moduleMap.put(
key,
new InstrumentationModule.Builder()
.srcPath(path.srcPath().replace("/javaagent", "").replace("/library", ""))
.srcPath(sanitizePathName(rootPath, path.srcPath()))
.instrumentationName(path.instrumentationName())
.namespace(path.namespace())
.group(path.group())
Expand All @@ -61,16 +62,21 @@ public static List<InstrumentationModule> convertToInstrumentationModules(
return new ArrayList<>(moduleMap.values());
}

private static String sanitizePathName(String rootPath, String path) {
return path.replace(rootPath, "").replace("/javaagent", "").replace("/library", "");
}

/**
* Traverses the given root directory to find all instrumentation paths and then analyzes them.
* Extracts version information from each instrumentation's build.gradle file, and other
* information from metadata.yaml files.
* Extracts version information from each instrumentation's build.gradle file, metric data from
* files in the .telemetry directories, and other information from metadata.yaml files.
*
* @return a list of {@link InstrumentationModule}
*/
List<InstrumentationModule> analyze() throws JsonProcessingException {
List<InstrumentationModule> analyze() throws IOException {
List<InstrumentationPath> paths = fileManager.getInstrumentationPaths();
List<InstrumentationModule> modules = convertToInstrumentationModules(paths);
List<InstrumentationModule> modules =
convertToInstrumentationModules(fileManager.rootDir(), paths);

for (InstrumentationModule module : modules) {
List<String> gradleFiles = fileManager.findBuildGradleFiles(module.getSrcPath());
Expand All @@ -86,12 +92,10 @@ List<InstrumentationModule> analyze() throws JsonProcessingException {
}
}

String emittedMetrics = fileManager.getMetrics(module.getSrcPath());
if (emittedMetrics != null) {
EmittedMetrics metrics = YamlHelper.emittedMetricsParser(emittedMetrics);
if (metrics != null && metrics.getMetrics() != null) {
module.setMetrics(metrics.getMetrics());
}
EmittedMetrics metrics =
MetricParser.getMetricsFromFiles(fileManager.rootDir(), module.getSrcPath());
if (!metrics.getMetrics().isEmpty()) {
module.setMetrics(metrics.getMetrics());
}
}
return modules;
Expand All @@ -100,7 +104,7 @@ List<InstrumentationModule> analyze() throws JsonProcessingException {
void analyzeVersions(List<String> files, InstrumentationModule module) {
Map<InstrumentationType, Set<String>> versions = new HashMap<>();
for (String file : files) {
String fileContents = fileManager.readFileToString(file);
String fileContents = FileManager.readFileToString(file);
if (fileContents == null) {
continue;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.instrumentation.docs.parsers;

import io.opentelemetry.instrumentation.docs.internal.EmittedMetrics;
import io.opentelemetry.instrumentation.docs.utils.FileManager;
import io.opentelemetry.instrumentation.docs.utils.YamlHelper;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import java.util.stream.Stream;

public class MetricParser {
private static final Logger logger = Logger.getLogger(MetricParser.class.getName());

/**
* Looks for metric files in the .telemetry directory, and combines them into a single list of
* metrics.
*
* @param instrumentationDirectory the directory to traverse
* @return contents of aggregated files
*/
public static EmittedMetrics getMetricsFromFiles(
String rootDir, String instrumentationDirectory) {
StringBuilder metricsContent = new StringBuilder("metrics:\n");
Path telemetryDir = Paths.get(rootDir + "/" + instrumentationDirectory, ".telemetry");

if (Files.exists(telemetryDir) && Files.isDirectory(telemetryDir)) {
try (Stream<Path> files = Files.list(telemetryDir)) {
files
.filter(path -> path.getFileName().toString().startsWith("metrics-"))
.forEach(
path -> {
String content = FileManager.readFileToString(path.toString());
if (content != null) {
// Skip the first line of yaml ("metrics:") so we can aggregate into one list
int firstNewline = content.indexOf('\n');
if (firstNewline != -1) {
String contentWithoutFirstLine = content.substring(firstNewline + 1);
metricsContent.append(contentWithoutFirstLine);
}
}
});
} catch (IOException e) {
logger.severe("Error reading metrics files: " + e.getMessage());
}
}

return parseMetrics(metricsContent.toString());
}

/**
* Takes in a raw string representation of the aggregated EmittedMetrics yaml, deduplicates the
* metrics by name and then returns a new EmittedMetrics object.
*
* @param input raw string representation of EmittedMetrics yaml
* @return EmittedMetrics
*/
// visible for testing
public static EmittedMetrics parseMetrics(String input) {
EmittedMetrics metrics = YamlHelper.emittedMetricsParser(input);
if (metrics.getMetrics() == null) {
return new EmittedMetrics(Collections.emptyList());
}

// deduplicate metrics by name
Map<String, EmittedMetrics.Metric> deduplicatedMetrics = new HashMap<>();
for (EmittedMetrics.Metric metric : metrics.getMetrics()) {
deduplicatedMetrics.put(metric.getName(), metric);
}

List<EmittedMetrics.Metric> uniqueMetrics = new ArrayList<>(deduplicatedMetrics.values());
return new EmittedMetrics(uniqueMetrics);
}

private MetricParser() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,17 @@
import java.util.stream.Stream;
import javax.annotation.Nullable;

public class FileManager {
public record FileManager(String rootDir) {
private static final Logger logger = Logger.getLogger(FileManager.class.getName());
private final String rootDir;

public FileManager(String rootDir) {
this.rootDir = rootDir;
}

public List<InstrumentationPath> getInstrumentationPaths() {
Path rootPath = Paths.get(rootDir);
public List<InstrumentationPath> getInstrumentationPaths() throws IOException {
Path rootPath = Paths.get(rootDir + "instrumentation");

try (Stream<Path> walk = Files.walk(rootPath)) {
return walk.filter(Files::isDirectory)
.filter(dir -> isValidInstrumentationPath(dir.toString()))
.map(dir -> parseInstrumentationPath(dir.toString()))
.collect(Collectors.toList());
} catch (IOException e) {
logger.severe("Error traversing directory: " + e.getMessage());
return new ArrayList<>();
}
}

Expand Down Expand Up @@ -85,7 +77,7 @@ public static boolean isValidInstrumentationPath(String filePath) {
}

public List<String> findBuildGradleFiles(String instrumentationDirectory) {
Path rootPath = Paths.get(instrumentationDirectory);
Path rootPath = Paths.get(rootDir + instrumentationDirectory);

try (Stream<Path> walk = Files.walk(rootPath)) {
return walk.filter(Files::isRegularFile)
Expand All @@ -103,49 +95,20 @@ public List<String> findBuildGradleFiles(String instrumentationDirectory) {

@Nullable
public String getMetaDataFile(String instrumentationDirectory) {
String metadataFile = instrumentationDirectory + "/metadata.yaml";
String metadataFile = rootDir + instrumentationDirectory + "/metadata.yaml";
if (Files.exists(Paths.get(metadataFile))) {
return readFileToString(metadataFile);
}
return null;
}

@Nullable
public String readFileToString(String filePath) {
public static String readFileToString(String filePath) {
try {
return Files.readString(Paths.get(filePath));
} catch (IOException e) {
logger.severe("Error reading file: " + e.getMessage());
return null;
}
}

/**
* Looks for metric files in the .telemetry directory
*
* @param instrumentationDirectory the directory to traverse
* @return contents of file
*/
public String getMetrics(String instrumentationDirectory) {
StringBuilder metricsContent = new StringBuilder();
Path telemetryDir = Paths.get(instrumentationDirectory, ".telemetry");

if (Files.exists(telemetryDir) && Files.isDirectory(telemetryDir)) {
try (Stream<Path> files = Files.list(telemetryDir)) {
files
.filter(path -> path.getFileName().toString().startsWith("metrics-"))
.forEach(
path -> {
String content = readFileToString(path.toString());
if (content != null) {
metricsContent.append(content).append("\n");
}
});
} catch (IOException e) {
logger.severe("Error reading metrics files: " + e.getMessage());
}
}

return metricsContent.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ void testConvertToInstrumentationModule() {
InstrumentationType.LIBRARY));

List<InstrumentationModule> modules =
InstrumentationAnalyzer.convertToInstrumentationModules(paths);
InstrumentationAnalyzer.convertToInstrumentationModules("test", paths);

assertThat(modules.size()).isEqualTo(2);

Expand Down
Loading
Loading