-
Notifications
You must be signed in to change notification settings - Fork 324
🪞 10310 - Add JMX MBean for getting tracer flare files #10435
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
mcculls
wants to merge
1
commit into
master
Choose a base branch
from
community-pr-10310
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+453
−1
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
200 changes: 200 additions & 0 deletions
200
utils/flare-utils/src/main/java/datadog/flare/TracerFlareManager.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,200 @@ | ||
| package datadog.flare; | ||
|
|
||
| import datadog.trace.api.Config; | ||
| import datadog.trace.api.flare.TracerFlare; | ||
| import java.io.ByteArrayInputStream; | ||
| import java.io.ByteArrayOutputStream; | ||
| import java.io.IOException; | ||
| import java.lang.management.ManagementFactory; | ||
| import java.nio.charset.StandardCharsets; | ||
| import java.util.Base64; | ||
| import java.util.Map; | ||
| import java.util.zip.ZipEntry; | ||
| import java.util.zip.ZipInputStream; | ||
| import java.util.zip.ZipOutputStream; | ||
| import javax.management.InstanceAlreadyExistsException; | ||
| import javax.management.MBeanRegistrationException; | ||
| import javax.management.MBeanServer; | ||
| import javax.management.MalformedObjectNameException; | ||
| import javax.management.NotCompliantMBeanException; | ||
| import javax.management.ObjectName; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
|
|
||
| /** | ||
| * MBean implementation for managing and accessing tracer flare data. | ||
| * | ||
| * <p>This class provides JMX operations to list flare data sources and retrieve flare data either | ||
| * for individual sources or a complete flare archive. See {@link TracerFlareManagerMBean} for | ||
| * documentation on the exposed operations. | ||
| */ | ||
| public class TracerFlareManager implements TracerFlareManagerMBean { | ||
| private static final Logger LOGGER = LoggerFactory.getLogger(TracerFlareManager.class); | ||
|
|
||
| private final TracerFlareService flareService; | ||
| protected ObjectName mbeanName; | ||
|
|
||
| public TracerFlareManager(TracerFlareService flareService) { | ||
| this.flareService = flareService; | ||
| } | ||
|
|
||
| @Override | ||
| public String generateFullFlareZip() throws IOException { | ||
| TracerFlare.prepareForFlare(); | ||
|
|
||
| long currentMillis = System.currentTimeMillis(); | ||
| boolean dumpThreads = Config.get().isTriageEnabled() || LOGGER.isDebugEnabled(); | ||
| byte[] zipBytes = flareService.buildFlareZip(currentMillis, currentMillis, dumpThreads); | ||
| return Base64.getEncoder().encodeToString(zipBytes); | ||
| } | ||
|
|
||
| @Override | ||
| public String listFlareFiles() throws IOException { | ||
| TracerFlare.prepareForFlare(); | ||
|
|
||
| StringBuilder result = new StringBuilder(); | ||
|
|
||
| for (Map.Entry<String, String[]> entry : TracerFlareService.BUILT_IN_SOURCES.entrySet()) { | ||
| String sourceName = entry.getKey(); | ||
| String[] files = entry.getValue(); | ||
|
|
||
| for (String filename : files) { | ||
| result.append(sourceName).append(" ").append(filename).append("\n"); | ||
| } | ||
| } | ||
|
|
||
| for (TracerFlare.Reporter reporter : TracerFlare.getReporters()) { | ||
| try (ByteArrayOutputStream bytes = new ByteArrayOutputStream(); | ||
| ZipOutputStream zip = new ZipOutputStream(bytes)) { | ||
| reporter.addReportToFlare(zip); | ||
| zip.finish(); | ||
|
|
||
| try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes.toByteArray()); | ||
| ZipInputStream zis = new ZipInputStream(bais)) { | ||
| ZipEntry entry; | ||
| while ((entry = zis.getNextEntry()) != null) { | ||
| result | ||
| .append(reporter.getClass().getName()) | ||
| .append(" ") | ||
| .append(entry.getName()) | ||
| .append("\n"); | ||
| zis.closeEntry(); | ||
| } | ||
| } | ||
| } catch (IOException e) { | ||
| LOGGER.debug("Failed to inspect reporter {}", reporter.getClass().getName(), e); | ||
| } | ||
| } | ||
|
|
||
| return result.toString(); | ||
| } | ||
|
|
||
| @Override | ||
| public String getFlareFile(String sourceName, String filename) throws IOException { | ||
| final byte[] zipBytes; | ||
| if (isBuiltInSource(sourceName)) { | ||
| zipBytes = flareService.getBuiltInSourceZip(sourceName); | ||
| } else { | ||
| zipBytes = getReporterFile(sourceName); | ||
| } | ||
| return extractFileFromZip(zipBytes, filename); | ||
| } | ||
|
|
||
| private boolean isBuiltInSource(String sourceName) { | ||
| return TracerFlareService.BUILT_IN_SOURCES.containsKey(sourceName); | ||
| } | ||
|
|
||
| /** | ||
| * Generates flare data for a specific reporter. | ||
| * | ||
| * <p>The reporter's data is generated as a ZIP file, and the specified filename is extracted. If | ||
| * the file is text, it is returned as plain text; if binary, it is returned base64-encoded. | ||
| * | ||
| * @param reporterClassName the fully qualified class name of the reporter | ||
| * @return the zip file containing the reporter's content | ||
| * @throws IOException if an error occurs while generating the flare | ||
| */ | ||
| private byte[] getReporterFile(String reporterClassName) throws IOException { | ||
| TracerFlare.Reporter reporter = TracerFlare.getReporter(reporterClassName); | ||
| if (reporter == null) { | ||
| throw new IOException("Error: Reporter not found: " + reporterClassName); | ||
| } | ||
|
|
||
| reporter.prepareForFlare(); | ||
|
|
||
| try (ByteArrayOutputStream bytes = new ByteArrayOutputStream(); | ||
| ZipOutputStream zip = new ZipOutputStream(bytes)) { | ||
| reporter.addReportToFlare(zip); | ||
| zip.finish(); | ||
| return bytes.toByteArray(); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Extracts a specific file from a ZIP archive. | ||
| * | ||
| * <p>Searches through the ZIP entries for the specified filename and returns its content. If the | ||
| * file name ends in ".txt", it is returned as plain text; if binary, it is returned | ||
| * base64-encoded. | ||
| * | ||
| * @param zipBytes the ZIP file bytes | ||
| * @param filename the name of the file to extract | ||
| * @return the file content (plain text or base64-encoded binary) | ||
| * @throws IOException if an error occurs while reading the ZIP | ||
| */ | ||
| private String extractFileFromZip(byte[] zipBytes, String filename) throws IOException { | ||
| try (ByteArrayInputStream bais = new ByteArrayInputStream(zipBytes); | ||
| ZipInputStream zis = new ZipInputStream(bais)) { | ||
| ZipEntry entry; | ||
| while ((entry = zis.getNextEntry()) != null) { | ||
| if (entry.getName().equals(filename)) { | ||
| ByteArrayOutputStream content = new ByteArrayOutputStream(); | ||
| byte[] buffer = new byte[8192]; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be better to declare 8192 as static const, to avoid |
||
| int bytesRead; | ||
| while ((bytesRead = zis.read(buffer)) != -1) { | ||
| content.write(buffer, 0, bytesRead); | ||
| } | ||
| zis.closeEntry(); | ||
|
|
||
| byte[] contentBytes = content.toByteArray(); | ||
| if (entry.getName().endsWith(".txt")) { | ||
| return new String(contentBytes, StandardCharsets.UTF_8); | ||
| } else { | ||
| return Base64.getEncoder().encodeToString(contentBytes); | ||
| } | ||
| } | ||
| zis.closeEntry(); | ||
| } | ||
|
|
||
| throw new IOException("Failed to extract file: " + filename); | ||
| } | ||
| } | ||
|
|
||
| void registerMBean() { | ||
| MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); | ||
|
|
||
| try { | ||
| mbeanName = new ObjectName("datadog.flare:type=TracerFlare"); | ||
| mbs.registerMBean(this, mbeanName); | ||
| LOGGER.info("Registered TracerFlare MBean at {}", mbeanName); | ||
| } catch (MalformedObjectNameException | ||
| | InstanceAlreadyExistsException | ||
| | MBeanRegistrationException | ||
| | NotCompliantMBeanException e) { | ||
| LOGGER.warn("Failed to register TracerFlare MBean", e); | ||
| mbeanName = null; | ||
| } | ||
| } | ||
|
|
||
| void unregisterMBean() { | ||
| if (mbeanName != null) { | ||
| MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); | ||
| try { | ||
| mbs.unregisterMBean(mbeanName); | ||
| LOGGER.debug("Unregistered TracerFlare MBean"); | ||
| } catch (Exception e) { | ||
| LOGGER.warn("Failed to unregister TracerFlare MBean", e); | ||
| } | ||
| } | ||
| } | ||
| } | ||
53 changes: 53 additions & 0 deletions
53
utils/flare-utils/src/main/java/datadog/flare/TracerFlareManagerMBean.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| package datadog.flare; | ||
|
|
||
| import java.io.IOException; | ||
|
|
||
| /** | ||
| * MBean interface for managing and accessing tracer flare data. | ||
| * | ||
| * <p>This interface provides JMX operations to inspect flare data sources and generate flare data | ||
| * either for individual sources or as a complete ZIP archive. Sources include both registered | ||
| * reporters and built-in data (config, runtime, flare prelude, etc.). | ||
| */ | ||
| public interface TracerFlareManagerMBean { | ||
| /** | ||
| * Lists all available flare files from all sources. | ||
| * | ||
| * <p>Returns a newline-separated string where each line is formatted as "<source> | ||
| * <file>". This format makes it easy to pass the source and filename to {@link | ||
| * #getFlareFile(String, String)}. | ||
| * | ||
| * <p>Example output: | ||
| * | ||
| * <pre> | ||
| * config initial_config.txt | ||
| * ... | ||
| * datadog.trace.agent.core.CoreTracer tracer_health.txt | ||
| * ... | ||
| * </pre> | ||
| * | ||
| * @return newline-separated string listing all available files and their source name | ||
| * @throws IOException if an error occurs | ||
| */ | ||
| String listFlareFiles() throws IOException; | ||
|
|
||
| /** | ||
| * Returns a specific flare file by source name and filename. | ||
| * | ||
| * <p>If the file is text, it is returned as plain text; if binary, it is returned base64-encoded. | ||
| * | ||
| * @param sourceName the name of the source (reporter class name or built-in source name) | ||
| * @param filename the name of the file to retrieve | ||
| * @return the file content (plain text or base64-encoded binary) | ||
| * @throws IOException if an error occurs while generating or extracting the data | ||
| */ | ||
| String getFlareFile(String sourceName, String filename) throws IOException; | ||
|
|
||
| /** | ||
| * Generates a complete tracer flare as a ZIP file. | ||
| * | ||
| * @return base64-encoded ZIP file containing the complete flare data | ||
| * @throws IOException if an error occurs while generating the flare ZIP | ||
| */ | ||
| String generateFullFlareZip() throws IOException; | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mhlidd Would you mind to review changes related to configuration, as you have a lot of experience with it?