Skip to content

Add more properties to BuiltInProperty#6683

Open
PreAgile wants to merge 4 commits intoline:mainfrom
PreAgile:feature/add-builtin-properties
Open

Add more properties to BuiltInProperty#6683
PreAgile wants to merge 4 commits intoline:mainfrom
PreAgile:feature/add-builtin-properties

Conversation

@PreAgile
Copy link
Copy Markdown

Motivation:

BuiltInProperty currently provides a limited set of properties compared to
AccessLogComponent's RequestLogComponent. Properties such as request/response
timing, content preview, serialization format, session protocol, and host are
available in access log formatting but cannot be exported to MDC via
RequestContextExportingAppender.

Modifications:

  • Add 10 timing properties: req.start_time_millis, req.end_time_millis,
    req.duration_nanos, req.duration_millis, res.start_time_millis,
    res.end_time_millis, res.duration_nanos, res.duration_millis,
    total_duration_nanos, total_duration_millis
  • Add 2 content preview properties: req.content_preview, res.content_preview
  • Add 3 protocol properties: serialization.format, session.protocol, host
  • elapsed_nanos remains for backward compatibility; total_duration_* is added
    for alignment with AccessLogComponent
  • req.content_preview / res.content_preview return only the content preview
    without falling back to RPC request parameters, unlike req.content / res.content

Result:

@CLAassistant
Copy link
Copy Markdown

CLAassistant commented Mar 27, 2026

CLA assistant check
All committers have signed the CLA.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 27, 2026

📝 Walkthrough

Walkthrough

This PR adds new BuiltInProperty enums exposing request/response start/end timestamps, durations (nanos/millis), total durations, content previews, serialization format, session protocol, and host; and updates tests to assert and validate these exports.

Changes

Cohort / File(s) Summary
Built-in Properties Addition
core/src/main/java/com/linecorp/armeria/common/logging/BuiltInProperty.java
Added enum constants for req.start_time_millis, req.end_time_millis, req.duration_nanos, req.duration_millis, res.start_time_millis, res.end_time_millis, res.duration_nanos, res.duration_millis, total_duration_nanos, total_duration_millis, req.content_preview, res.content_preview, serialization.format, session.protocol, and host. Each property returns a string only when the corresponding RequestLogProperty is available; end times computed by adding durations to start epoch-millis; host prefers :authority (ignoring "?") or falls back to remote address host.
Core Logging Tests
core/src/test/java/com/linecorp/armeria/common/logging/RequestContextExporterTest.java
Expanded expected non-null built-in keys to include timing and metadata fields. Added shouldExportNewBuiltInProperties() to verify session protocol, serialization format, host, and total_duration_nanos consistency; added shouldExportContentPreview() to verify req.content_preview and res.content_preview.
Logback Integration Tests
logback/logback12/src/test/java/com/linecorp/armeria/common/logback/RequestContextExportingAppenderTest.java
Updated MDC expectations across scenarios to include serialization.format, session.protocol, host, and the new timing keys. Added testContentPreview() asserting content preview MDC entries and testTimingValueConsistency() validating timing-value consistency and non-negativity.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 I hopped through logs at break of dawn,

I found time stamps on the lawn,
Durations, hosts, and content peek,
Now exports whisper what they seek,
— a rabbit cheers for logging strong 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title 'Add more properties to BuiltInProperty' is clear, concise, and accurately reflects the main objective of adding new properties to the BuiltInProperty enum.
Description check ✅ Passed The pull request description provides comprehensive motivation, detailed modifications list, and expected results, all directly related to the changeset of adding timing, content preview, and protocol properties.
Linked Issues check ✅ Passed The pull request successfully implements the objectives from issue #4403 by adding 15 new BuiltInProperty constants that expand properties for RequestContextExportingAppender to align with AccessLogComponent, including timing, content preview, and protocol/host properties.
Out of Scope Changes check ✅ Passed All changes are directly within scope: 15 new BuiltInProperty constants, test updates in two test files to verify the new properties, with no extraneous modifications outside the PR objectives.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

PreAgile added a commit to PreAgile/armeria that referenced this pull request Mar 27, 2026
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 27, 2026

Codecov Report

❌ Patch coverage is 89.55224% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 74.02%. Comparing base (8150425) to head (817561e).
⚠️ Report is 403 commits behind head on main.

Files with missing lines Patch % Lines
...necorp/armeria/common/logging/BuiltInProperty.java 89.55% 2 Missing and 5 partials ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main    #6683      +/-   ##
============================================
- Coverage     74.46%   74.02%   -0.44%     
- Complexity    22234    24113    +1879     
============================================
  Files          1963     2173     +210     
  Lines         82437    90442    +8005     
  Branches      10764    11858    +1094     
============================================
+ Hits          61385    66950    +5565     
- Misses        15918    17881    +1963     
- Partials       5134     5611     +477     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Contributor

@jrhee17 jrhee17 left a comment

Choose a reason for hiding this comment

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

👍 👍

@jrhee17 jrhee17 added this to the 1.38.0 milestone Mar 27, 2026
HOST("host", log -> {
if (log.isAvailable(RequestLogProperty.REQUEST_HEADERS)) {
final String authority = log.requestHeaders().authority();
if (authority != null && !"?".equals(authority)) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Question: I'm wondering why we need to compare ??

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Note) The changes in this file are mostly directly ported from AccessLogComponent.
I agree we can change the logic, but we may want to change both sides if we decide to update in this PR or leave for future works, I'm fine with either direction.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If so, let's keep it as is and fix it separately if necessary.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Understood. The ? check is technically unreachable here since isAvailable(REQUEST_HEADERS) guards against the dummy headers, but keeping it as is to stay consistent with AccessLogComponent — if we change it, both sides should be updated together.

}),

/**
* {@code "host"} - the authority of the request, derived from the {@code :authority} header.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Note that log.requestHeaders().authority() falls back to Host header for HTTP/1.1

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thanks for the note. I see that RequestHeaders.authority() internally falls back to the Host header for HTTP/1.1, so this property works regardless of the protocol version. Updated the Javadoc to mention the Host header fallback for HTTP/1.1.

*/
RES_DURATION_MILLIS("res.duration_millis", log -> {
if (log.isAvailable(RequestLogProperty.RESPONSE_END_TIME)) {
return String.valueOf(Duration.ofNanos(log.responseDurationNanos()).toMillis());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Duration.ofNanos() creates an instance just for this time conversion.

Suggested change
return String.valueOf(Duration.ofNanos(log.responseDurationNanos()).toMillis());
return String.valueOf(TimeUnit.NANOSECONDS.toMillis(log.responseDurationNanos()));

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thanks for the suggestion. Replaced all Duration.ofNanos().toMillis() with TimeUnit.NANOSECONDS.toMillis() to avoid unnecessary heap allocation in the converter lambdas. Also applied the same principle to Instant usages in REQ_END_TIME_MILLIS and RES_END_TIME_MILLIS — replaced with plain millis arithmetic since the existing converters in this file (e.g. ELAPSED_NANOS) consistently use direct primitive-to-String conversion without intermediate objects.

@ikhoon
Copy link
Copy Markdown
Contributor

ikhoon commented Apr 2, 2026

Thank you for your interest in the Armeria repository and for contributing to it. It seems you are interested in other issues as well, but please understand that reviews consume a significant amount of our resources, so they may not be completed quickly. If your goal is to improve your understanding of Armeria core, I would recommend creating PRs without using AI.

PreAgile added a commit to PreAgile/armeria that referenced this pull request Apr 2, 2026
- LINE Pay Backend Engineer JD 분석 (필수/우대 요건)
- Armeria 기여 ↔ JD 연결 테이블 (대량 트래픽, 분산시스템, 감사 로깅)
- 면접 스토리 구체적 에피소드 정리 (PR line#6683, issue-6385)
- 우선순위: 실제 서비스 경험 > CS 기본기 > Armeria 기여(보조)
- README에 커리어 전략 문서 링크 추가

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@ikhoon ikhoon left a comment

Choose a reason for hiding this comment

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

👍👍

PreAgile and others added 2 commits April 3, 2026 23:46
- Replace Duration.ofNanos().toMillis() with TimeUnit.NANOSECONDS.toMillis()
  for REQ_DURATION_MILLIS, RES_DURATION_MILLIS, and TOTAL_DURATION_MILLIS
- Replace Instant-based end time calculation with plain millis arithmetic
  for REQ_END_TIME_MILLIS and RES_END_TIME_MILLIS
- Update HOST Javadoc to note Host header fallback for HTTP/1.1
@PreAgile PreAgile force-pushed the feature/add-builtin-properties branch from 0180453 to 92390d3 Compare April 3, 2026 14:56
@PreAgile
Copy link
Copy Markdown
Author

PreAgile commented Apr 3, 2026

Thank you for the detailed review. I've pushed a new commit addressing each point — switching to TimeUnit for lightweight conversion and clarifying the HOST Javadoc. Going through the review helped me understand how BuiltInProperty's converter lambdas differ from AccessLogComponent's resolvers in terms of invocation frequency and allocation sensitivity.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
logback/logback12/src/test/java/com/linecorp/armeria/common/logback/RequestContextExportingAppenderTest.java (1)

677-701: Optionally strengthen timing consistency assertions.

Current checks validate equality/non-negativity; you can also assert millis values are derived from nanos to catch conversion regressions.

♻️ Optional tightening
     void testTimingValueConsistency() throws Exception {
@@
             final ILoggingEvent e = log(events);
             final Map<String, String> mdc = e.getMDCPropertyMap();
+            assertThat(mdc).containsKeys("elapsed_nanos", "total_duration_nanos", "total_duration_millis",
+                                         "req.duration_nanos", "req.duration_millis");
             // total_duration_nanos and elapsed_nanos should have the same value.
             assertThat(mdc.get("total_duration_nanos")).isEqualTo(mdc.get("elapsed_nanos"));
-            // duration values should be non-negative.
-            assertThat(Long.parseLong(mdc.get("total_duration_nanos"))).isNotNegative();
-            assertThat(Long.parseLong(mdc.get("total_duration_millis"))).isNotNegative();
-            assertThat(Long.parseLong(mdc.get("req.duration_nanos"))).isNotNegative();
-            assertThat(Long.parseLong(mdc.get("req.duration_millis"))).isNotNegative();
+            final long totalDurationNanos = Long.parseLong(mdc.get("total_duration_nanos"));
+            final long totalDurationMillis = Long.parseLong(mdc.get("total_duration_millis"));
+            final long reqDurationNanos = Long.parseLong(mdc.get("req.duration_nanos"));
+            final long reqDurationMillis = Long.parseLong(mdc.get("req.duration_millis"));
+
+            // duration values should be non-negative.
+            assertThat(totalDurationNanos).isNotNegative();
+            assertThat(totalDurationMillis).isNotNegative();
+            assertThat(reqDurationNanos).isNotNegative();
+            assertThat(reqDurationMillis).isNotNegative();
+
+            // millis values should match nanos-to-millis conversion.
+            assertThat(totalDurationMillis)
+                    .isEqualTo(java.util.concurrent.TimeUnit.NANOSECONDS.toMillis(totalDurationNanos));
+            assertThat(reqDurationMillis)
+                    .isEqualTo(java.util.concurrent.TimeUnit.NANOSECONDS.toMillis(reqDurationNanos));
         }
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@logback/logback12/src/test/java/com/linecorp/armeria/common/logback/RequestContextExportingAppenderTest.java`
around lines 677 - 701, The test testTimingValueConsistency currently asserts
equality and non-negativity only; strengthen it by adding checks that the
millisecond fields are consistent with their nanosecond counterparts (i.e.,
total_duration_millis == total_duration_nanos / 1_000_000 and
req.duration_millis == req.duration_nanos / 1_000_000) using values pulled from
the MDC produced by log(events); update assertions in testTimingValueConsistency
(alongside prepare, newClientContext, and log usages) to parse nanos and millis
as longs and assert the integer division conversion matches to catch conversion
regressions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@logback/logback12/src/test/java/com/linecorp/armeria/common/logback/RequestContextExportingAppenderTest.java`:
- Around line 677-701: The test testTimingValueConsistency currently asserts
equality and non-negativity only; strengthen it by adding checks that the
millisecond fields are consistent with their nanosecond counterparts (i.e.,
total_duration_millis == total_duration_nanos / 1_000_000 and
req.duration_millis == req.duration_nanos / 1_000_000) using values pulled from
the MDC produced by log(events); update assertions in testTimingValueConsistency
(alongside prepare, newClientContext, and log usages) to parse nanos and millis
as longs and assert the integer division conversion matches to catch conversion
regressions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f77df26b-020b-4427-9e58-520ef9c5d1fd

📥 Commits

Reviewing files that changed from the base of the PR and between 0180453 and 92390d3.

📒 Files selected for processing (3)
  • core/src/main/java/com/linecorp/armeria/common/logging/BuiltInProperty.java
  • core/src/test/java/com/linecorp/armeria/common/logging/RequestContextExporterTest.java
  • logback/logback12/src/test/java/com/linecorp/armeria/common/logback/RequestContextExportingAppenderTest.java
🚧 Files skipped from review as they are similar to previous changes (2)
  • core/src/test/java/com/linecorp/armeria/common/logging/RequestContextExporterTest.java
  • core/src/main/java/com/linecorp/armeria/common/logging/BuiltInProperty.java

Copy link
Copy Markdown
Contributor

@minwoox minwoox left a comment

Choose a reason for hiding this comment

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

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add more properties to BuiltInProperty

5 participants