From f7234e31ca662329df3c52b7a07e09c8d41c2bdc Mon Sep 17 00:00:00 2001 From: Arata Nakafushiki <274594+raydive@users.noreply.github.com> Date: Thu, 6 Aug 2026 16:50:38 +0900 Subject: [PATCH] Add @WithSpan annotations for OpenTelemetry phase tracing Instrument Parser/HtmlRenderer processing phases with OpenTelemetry @WithSpan annotations so that traces show where markdown processing time is spent: - markdown.parse: Parser.parse(String/BasedSequence/Reader) - markdown.parse.blocks: block parsing loop, extracted into DocumentParser.parseBlocks() (behavior unchanged) - markdown.parse.pre_process_paragraphs / pre_process_blocks / inlines: existing DocumentParser phase methods - markdown.parse.post_process: PostProcessorManager.processDocument - markdown.render: HtmlRenderer.render(Node, Appendable, int), where all public render overloads converge The opentelemetry-instrumentation-annotations dependency is annotation-only (~20KB). Spans are created by a Java agent (dd-java-agent with dd.trace.otel.enabled=true, or opentelemetry-javaagent); without an agent the annotations are inert with no runtime effect. Co-Authored-By: Claude Fable 5 --- flexmark/pom.xml | 4 ++++ .../vladsch/flexmark/html/HtmlRenderer.java | 2 ++ .../com/vladsch/flexmark/parser/Parser.java | 4 ++++ .../parser/internal/DocumentParser.java | 21 +++++++++++++------ .../parser/internal/PostProcessorManager.java | 2 ++ pom.xml | 9 ++++++++ 6 files changed, 36 insertions(+), 6 deletions(-) diff --git a/flexmark/pom.xml b/flexmark/pom.xml index 16cf3116c..b39f5ceb2 100644 --- a/flexmark/pom.xml +++ b/flexmark/pom.xml @@ -62,6 +62,10 @@ com.vladsch.flexmark flexmark-util-visitor + + io.opentelemetry.instrumentation + opentelemetry-instrumentation-annotations + org.openjdk.jmh jmh-core diff --git a/flexmark/src/main/java/com/vladsch/flexmark/html/HtmlRenderer.java b/flexmark/src/main/java/com/vladsch/flexmark/html/HtmlRenderer.java index 91a9db8c5..7a41e81cf 100644 --- a/flexmark/src/main/java/com/vladsch/flexmark/html/HtmlRenderer.java +++ b/flexmark/src/main/java/com/vladsch/flexmark/html/HtmlRenderer.java @@ -18,6 +18,7 @@ import com.vladsch.flexmark.util.sequence.Escaping; import com.vladsch.flexmark.util.sequence.LineAppendable; import com.vladsch.flexmark.util.sequence.TagRange; +import io.opentelemetry.instrumentation.annotations.WithSpan; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -203,6 +204,7 @@ public void render(@NotNull Node node, @NotNull Appendable output) { * @param node node to render * @param output appendable to use for the output */ + @WithSpan("markdown.render") public void render(@NotNull Node node, @NotNull Appendable output, int maxTrailingBlankLines) { HtmlWriter htmlWriter = new HtmlWriter(output, htmlOptions.indentSize, htmlOptions.formatFlags, !htmlOptions.htmlBlockOpenTagEol, !htmlOptions.htmlBlockCloseTagEol); MainNodeRenderer renderer = new MainNodeRenderer(options, htmlWriter, node.getDocument()); diff --git a/flexmark/src/main/java/com/vladsch/flexmark/parser/Parser.java b/flexmark/src/main/java/com/vladsch/flexmark/parser/Parser.java index 22a93ce4d..17ccc6ea5 100644 --- a/flexmark/src/main/java/com/vladsch/flexmark/parser/Parser.java +++ b/flexmark/src/main/java/com/vladsch/flexmark/parser/Parser.java @@ -17,6 +17,7 @@ import com.vladsch.flexmark.util.sequence.BasedSequence; import com.vladsch.flexmark.util.sequence.ReplacedBasedSequence; import com.vladsch.flexmark.util.sequence.mappers.SpecialLeadInHandler; +import io.opentelemetry.instrumentation.annotations.WithSpan; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -353,6 +354,7 @@ public static Builder builder(DataHolder options) { * @param input the text to parse * @return the root node */ + @WithSpan("markdown.parse") public @NotNull Document parse(@NotNull BasedSequence input) { // NOTE: parser can only handle contiguous sequences with no out of base characters if (input instanceof ReplacedBasedSequence) { @@ -379,6 +381,7 @@ public static Builder builder(DataHolder options) { * @param input the text to parse * @return the root node */ + @WithSpan("markdown.parse") public @NotNull Document parse(@NotNull String input) { DocumentParser documentParser = new DocumentParser(options , blockParserFactories @@ -398,6 +401,7 @@ public static Builder builder(DataHolder options) { * @return the root node * @throws IOException when reading throws an exception */ + @WithSpan("markdown.parse") public @NotNull Document parseReader(@NotNull Reader input) throws IOException { DocumentParser documentParser = new DocumentParser(options , blockParserFactories diff --git a/flexmark/src/main/java/com/vladsch/flexmark/parser/internal/DocumentParser.java b/flexmark/src/main/java/com/vladsch/flexmark/parser/internal/DocumentParser.java index c4a539ecf..6cd3c85d0 100644 --- a/flexmark/src/main/java/com/vladsch/flexmark/parser/internal/DocumentParser.java +++ b/flexmark/src/main/java/com/vladsch/flexmark/parser/internal/DocumentParser.java @@ -18,6 +18,7 @@ import com.vladsch.flexmark.util.misc.CharPredicate; import com.vladsch.flexmark.util.sequence.BasedSequence; import com.vladsch.flexmark.util.sequence.PrefixedSubSequence; +import io.opentelemetry.instrumentation.annotations.WithSpan; import org.jetbrains.annotations.NotNull; import java.io.BufferedReader; @@ -271,16 +272,23 @@ public InlineParser getInlineParser() { */ public Document parse(CharSequence source) { BasedSequence input = BasedSequence.of(source); - int lineStart = 0; - int lineBreak; - int lineEOL; - int lineEnd; lineNumber = 0; documentBlockParser.initializeDocument(options, input); inlineParser.initializeDocument(documentBlockParser.getBlock()); currentPhase = ParserPhase.PARSE_BLOCKS; + parseBlocks(input); + + return finalizeAndProcess(); + } + + @WithSpan("markdown.parse.blocks") + private void parseBlocks(BasedSequence input) { + int lineStart = 0; + int lineBreak; + int lineEOL; + int lineEnd; while ((lineBreak = Parsing.findLineBreak(input, lineStart)) != -1) { BasedSequence line = input.subSequence(lineStart, lineBreak); @@ -308,8 +316,6 @@ public Document parse(CharSequence source) { incorporateLine(lineWithEOL); lineNumber++; } - - return finalizeAndProcess(); } public Document parse(Reader input) throws IOException { @@ -745,6 +751,7 @@ private void finalize(BlockParser blockParser) { /** * Walk through a block & children recursively, parsing string content into inline content where appropriate. */ + @WithSpan("markdown.parse.inlines") private void processInlines() { for (BlockParser blockParser : blockTracker.allBlockParsers()) { blockParser.parseInlines(inlineParser); @@ -938,6 +945,7 @@ private void preProcessParagraph(Paragraph block, List> blockTypes = new HashSet<>(); diff --git a/flexmark/src/main/java/com/vladsch/flexmark/parser/internal/PostProcessorManager.java b/flexmark/src/main/java/com/vladsch/flexmark/parser/internal/PostProcessorManager.java index 3d3749ef6..8021db187 100644 --- a/flexmark/src/main/java/com/vladsch/flexmark/parser/internal/PostProcessorManager.java +++ b/flexmark/src/main/java/com/vladsch/flexmark/parser/internal/PostProcessorManager.java @@ -12,6 +12,7 @@ import com.vladsch.flexmark.util.dependency.DependencyResolver; import com.vladsch.flexmark.util.dependency.DependentItem; import com.vladsch.flexmark.util.dependency.DependentItemMap; +import io.opentelemetry.instrumentation.annotations.WithSpan; import java.util.*; @@ -50,6 +51,7 @@ public static List calculatePostProcessors(DataHol return dependencyStages; } + @WithSpan("markdown.parse.post_process") public static Document processDocument(Document document, List processorDependencies) { if (!processorDependencies.isEmpty()) { PostProcessorManager manager = new PostProcessorManager(processorDependencies); diff --git a/pom.xml b/pom.xml index 679b15aa6..659fd74ed 100644 --- a/pom.xml +++ b/pom.xml @@ -538,6 +538,15 @@ ${project.version} + + + io.opentelemetry.instrumentation + opentelemetry-instrumentation-annotations + 2.16.0 + + junit