Introduce log maskers for `AnnotatedService`
Motivation:
This PR includes changes for #6231 .
While logging request/response logs provides developers more tools for debugging, logging sensitive data runs the risk of exposing certain information outside of the intended scope. For this reason, there have been multiple attempts to add sanitization at #3795 and #4267.
This PR attempts to provide users an easier way to mask logging data by recursively introspecting fields for cross-cutting concerns. In detail, users may determine whether to mask a POJO field or not depending on annotations.
The following illustrates a sample usage where all fields with a @ShouldMask annotation are nullified:
@Retention(RetentionPolicy.RUNTIME)
public @interface ShouldMask {}
val contentSanitizer = ContentSanitizer.builder()
.fieldMaskerSelector(FieldMaskerSelector.ofBean(info -> {
final ShouldMask maskerAnn = info.getAnnotation(ShouldMask.class);
if (maskerAnn == null) {
return FieldMasker.fallthrough();
}
return FieldMasker.nullify();
}))
.buildForText()
LoggingService.builder()
.logWriter(LogWriter.of(LogFormatter.builderForText()
.contentSanitizer(contentSanitizer)
.build()))
.newDecorator()
Note that the default serializers for AnnotatedRequest and AnnotatedResponse have been removed.
I believe this wouldn't be an issue since
- Users will be using
ContentPreviewingServicefor annotated services anyways -
JsonLogFormatternaively appliesObjectMapper- even now Thrift, gRPC content probably wasn't correctly serialized anyways It's probably worth tackling this issue when renovatingJsonLogFormatterrather than in this PR
Modifications:
- Serializers for
AnnotatedRequestandAnnotatedResponsehave been added- Special logic is added to unwrap CF or ignore armeria internal types that don't support Jackson.
- Log masking related APIs are introduced
-
BeanFieldMaskerSelectoris introduced so users can determine how to mask a field depending on the annotation information -
BeanFieldInfois introduced which contains annotation information of a bean field.-
JacksonBeanFieldInfois created while recursively iterating fields viaJackson.AnnotatedBeanFieldInfois created fromAnnotatedServicefor parameters or return values.
-
-
FieldMaskeris introduced which actually performs the masking of a field value.- As it may be complicated to implement
FieldMaskerdirectly,FieldMaskerBuilderis introduced so users can easily create aFieldMaskerin a type-safe manner.
- As it may be complicated to implement
-
FieldMaskerSelectorProvideris introduced to allowFieldMaskerSelectorcustomization for different protocols (thrift, gRPC)-
BeanFieldMaskerSelectorProvideris implemented which customizes anObjectMapperto correctly handle log masking forAnnotatedService
-
-
MaskingBeanDeserializerModifierandMaskingBeanSerializerModifierare added, which applies the appropriateFieldMaskerduring serde.
-
Result:
- Users can determine whether to mask a POJO field via annotations
Codecov Report
Attention: Patch coverage is 86.46154% with 44 lines in your changes missing coverage. Please review.
Project coverage is 74.71%. Comparing base (
8150425) to head (abc2164). Report is 102 commits behind head on main.
Additional details and impacted files
@@ Coverage Diff @@
## main #6232 +/- ##
============================================
+ Coverage 74.46% 74.71% +0.25%
- Complexity 22234 22537 +303
============================================
Files 1963 1998 +35
Lines 82437 83227 +790
Branches 10764 10801 +37
============================================
+ Hits 61385 62186 +801
+ Misses 15918 15896 -22
- Partials 5134 5145 +11
:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.
:rocket: New features to boost your workflow:
- :snowflake: Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
- :package: JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
🔍 Build Scan® (commit: 4ca67f691466668c8c5f428de370e01a091635cc)
| Job name | Status | Build Scan® |
|---|---|---|
| build-ubicloud-standard-16-jdk-8 | ✅ | https://ge.armeria.dev/s/rtp6uljhydoby |
| build-ubicloud-standard-16-jdk-21-snapshot-blockhound | ❌ (failure) | https://ge.armeria.dev/s/ltr3y23brydjm |
| build-ubicloud-standard-16-jdk-17-min-java-17-coverage | ❌ (failure) | https://ge.armeria.dev/s/gwctwvmqthaq2 |
| build-ubicloud-standard-16-jdk-17-min-java-11 | ✅ | https://ge.armeria.dev/s/se4s3lef3cpzm |
| build-ubicloud-standard-16-jdk-17-leak | ✅ | https://ge.armeria.dev/s/a2w425ifgxft6 |
| build-ubicloud-standard-16-jdk-11 | ✅ | https://ge.armeria.dev/s/nilwex4bomzji |
| build-macos-latest-jdk-21 | ✅ | https://ge.armeria.dev/s/4j6s2wx7be2nm |
Ready for review
Bump) Ready for review