Skip to content

Commit 596bfef

Browse files
committed
feat: mdc 계측용 코드 추가
1 parent d443a91 commit 596bfef

File tree

11 files changed

+344
-95
lines changed

11 files changed

+344
-95
lines changed

main/src/main/java/org/sopt/makers/crew/main/global/filter/MdcLoggingFilter.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
package org.sopt.makers.crew.main.global.filter;
22

33
import static org.sopt.makers.crew.main.global.metrics.SpikeApplyMetrics.CLIENT_IP_ATTRIBUTE;
4+
import static org.sopt.makers.crew.main.global.metrics.SpikeApplyMetrics.METRIC_MDC_TOTAL;
5+
import static org.sopt.makers.crew.main.global.metrics.SpikeApplyMetrics.OUTCOME_SUCCESS;
46
import static org.sopt.makers.crew.main.global.metrics.SpikeApplyMetrics.REQUEST_INFO_ATTRIBUTE;
57
import static org.sopt.makers.crew.main.global.metrics.SpikeApplyMetrics.TRACE_ID_ATTRIBUTE;
68

79
import java.io.IOException;
810
import java.util.UUID;
911

1012
import org.slf4j.MDC;
13+
import org.sopt.makers.crew.main.global.metrics.SpikeApplyMetricRecorder;
1114
import org.sopt.makers.crew.main.global.metrics.SpikeApplyRequestSupport;
15+
import org.sopt.makers.crew.main.global.metrics.SpikeApplyRuntimeConfig;
1216
import org.springframework.stereotype.Component;
1317
import org.springframework.web.filter.OncePerRequestFilter;
1418

@@ -29,11 +33,15 @@ public class MdcLoggingFilter extends OncePerRequestFilter {
2933
private static final String X_FORWARDED_FOR = "X-Forwarded-For";
3034
private static final String X_REAL_IP = "X-Real-IP";
3135
private final SpikeApplyRequestSupport spikeApplyRequestSupport;
36+
private final SpikeApplyMetricRecorder spikeApplyMetricRecorder;
3237

3338
@Override
3439
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
3540
FilterChain filterChain) throws ServletException, IOException {
41+
boolean isSpikeApplyRequest = spikeApplyRequestSupport.isSpikeApplyRequest(request);
3642
try {
43+
long mdcSetupStart = isSpikeApplyRequest ? System.nanoTime() : 0L;
44+
String outcome = OUTCOME_SUCCESS;
3745
boolean persistDiagnosticAttributes = spikeApplyRequestSupport.shouldPersistDiagnosticAttributes(request);
3846
String traceId = resolveTraceId(request);
3947
String clientIp = spikeApplyRequestSupport.shouldCaptureClientIp(request) ? resolveClientIp(request) : null;
@@ -52,7 +60,18 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
5260
}
5361
response.setHeader(X_CORRELATION_ID, traceId);
5462
response.setHeader(X_REQUEST_ID, traceId);
63+
if (isSpikeApplyRequest) {
64+
spikeApplyMetricRecorder.recordTimer(
65+
METRIC_MDC_TOTAL,
66+
SpikeApplyRuntimeConfig.currentTxMode(),
67+
SpikeApplyRuntimeConfig.currentGate(),
68+
outcome,
69+
System.nanoTime() - mdcSetupStart
70+
);
71+
}
5572
filterChain.doFilter(request, response);
73+
} catch (ServletException | IOException | RuntimeException exception) {
74+
throw exception;
5675
} finally {
5776
MDC.clear();
5877
}

main/src/main/java/org/sopt/makers/crew/main/global/jwt/authenticator/JwtAuthenticator.java

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,8 @@ public MakersAuthentication authenticate(String token) {
105105
outcome,
106106
totalNanos
107107
);
108-
if (diagnosticsEnabled) {
108+
if (diagnosticsEnabled && spikeDiagnosticProperties.isDetailedTimerEnabled(
109+
METRIC_JWT_VERIFY_UNATTRIBUTED_TOTAL)) {
109110
spikeApplyMetricRecorder.recordTimer(
110111
METRIC_JWT_VERIFY_UNATTRIBUTED_TOTAL,
111112
SpikeApplyRuntimeConfig.currentTxMode(),
@@ -125,7 +126,7 @@ public MakersAuthentication authenticate(String token) {
125126
* @return 사용자 인증 정보 객체
126127
*/
127128
private MakersAuthentication toAuthentication(JWTClaimsSet claims, boolean shouldRecord, StageAccumulator stageAccumulator) {
128-
if (!shouldRecord) {
129+
if (!shouldMeasureDetailedTimer(METRIC_JWT_TO_AUTHENTICATION_TOTAL, shouldRecord)) {
129130
String userId = claims.getSubject();
130131
List<String> roles = (List<String>)claims.getClaim(ROLES);
131132
return new MakersAuthentication(userId, roles);
@@ -145,7 +146,7 @@ private MakersAuthentication toAuthentication(JWTClaimsSet claims, boolean shoul
145146
}
146147

147148
private SignedJWT parseJwt(String token, boolean shouldRecord, StageAccumulator stageAccumulator) throws ParseException {
148-
if (!shouldRecord) {
149+
if (!shouldMeasureDetailedTimer(METRIC_JWT_PARSE_TOTAL, shouldRecord)) {
149150
return SignedJWT.parse(token);
150151
}
151152
long start = System.nanoTime();
@@ -161,7 +162,7 @@ private SignedJWT parseJwt(String token, boolean shouldRecord, StageAccumulator
161162
}
162163

163164
private String extractKeyId(SignedJWT jwt, boolean shouldRecord, StageAccumulator stageAccumulator) {
164-
if (!shouldRecord) {
165+
if (!shouldMeasureDetailedTimer(METRIC_JWT_EXTRACT_KID_TOTAL, shouldRecord)) {
165166
return extractKeyId(jwt);
166167
}
167168
long start = System.nanoTime();
@@ -177,7 +178,7 @@ private String extractKeyId(SignedJWT jwt, boolean shouldRecord, StageAccumulato
177178
}
178179

179180
private PublicKey getPublicKey(String kid, boolean shouldRecord, StageAccumulator stageAccumulator) {
180-
if (!shouldRecord) {
181+
if (!shouldMeasureDetailedTimer(METRIC_JWT_GET_PUBLIC_KEY_TOTAL, shouldRecord)) {
181182
return loadPublicKey(kid);
182183
}
183184
long start = System.nanoTime();
@@ -215,7 +216,7 @@ private PublicKey getPublicKey(String kid, boolean shouldRecord) {
215216
*/
216217
private VerificationResult verifyWithRetry(SignedJWT jwt, String kid, PublicKey publicKey, boolean shouldRecord,
217218
StageAccumulator stageAccumulator) {
218-
if (!shouldRecord) {
219+
if (!shouldMeasureDetailedTimer(METRIC_JWT_VERIFY_WITH_RETRY_TOTAL, shouldRecord)) {
219220
try {
220221
return new VerificationResult(verify(jwt, publicKey, false), false);
221222
} catch (JOSEException | ParseException e) {
@@ -289,7 +290,7 @@ private JWTClaimsSet verify(SignedJWT jwt, PublicKey publicKey, boolean shouldRe
289290
}
290291

291292
private boolean verifySignature(SignedJWT jwt, JWSVerifier verifier, boolean shouldRecord) throws JOSEException {
292-
if (!shouldRecord) {
293+
if (!shouldMeasureDetailedTimer(METRIC_JWT_SIGNATURE_VERIFY_TOTAL, shouldRecord)) {
293294
return jwt.verify(verifier);
294295
}
295296
long start = System.nanoTime();
@@ -306,7 +307,7 @@ private boolean verifySignature(SignedJWT jwt, JWSVerifier verifier, boolean sho
306307

307308
private JWTClaimsSet validateClaims(SignedJWT jwt, boolean signatureValid, boolean shouldRecord) throws
308309
ParseException {
309-
if (!shouldRecord) {
310+
if (!shouldMeasureDetailedTimer(METRIC_JWT_CLAIMS_VALIDATE_TOTAL, shouldRecord)) {
310311
JWTClaimsSet claims = jwt.getJWTClaimsSet();
311312
boolean issuerValid = issuer.equals(claims.getIssuer());
312313
boolean notExpired = skipExpirationCheck || claims.getExpirationTime().after(new Date());
@@ -348,7 +349,9 @@ private void recordMeasuredStage(
348349
StageAccumulator stageAccumulator
349350
) {
350351
long durationNanos = System.nanoTime() - start;
351-
stageAccumulator.add(durationNanos);
352+
if (shouldMeasureDetailedTimer(metricName, shouldRecord)) {
353+
stageAccumulator.add(durationNanos);
354+
}
352355
recordTimer(metricName, durationNanos, outcome, shouldRecord);
353356
}
354357

@@ -374,7 +377,7 @@ private void recordTimer(String metricName, long durationNanos, String outcome,
374377
}
375378

376379
private void recordRetryObservation(String metricName, boolean shouldRecord) {
377-
if (!shouldRecord) {
380+
if (!(shouldRecord && spikeDiagnosticProperties.isDetailedSummaryEnabled(metricName))) {
378381
return;
379382
}
380383
spikeApplyMetricRecorder.recordSummary(
@@ -390,6 +393,10 @@ private String extractKeyId(SignedJWT jwt) {
390393
return jwt.getHeader().getKeyID();
391394
}
392395

396+
private boolean shouldMeasureDetailedTimer(String metricName, boolean shouldRecord) {
397+
return shouldRecord && spikeDiagnosticProperties.isDetailedTimerEnabled(metricName);
398+
}
399+
393400
private static final class StageAccumulator {
394401
private long totalNanos;
395402

main/src/main/java/org/sopt/makers/crew/main/global/jwt/provider/JwkProvider.java

Lines changed: 82 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -65,18 +65,61 @@ public JwkProvider(
6565
*/
6666
public PublicKey getPublicKey(String kid) {
6767
boolean shouldRecord = "true".equals(MDC.get(MDC_ACTIVE_KEY));
68-
if (!(shouldRecord && spikeDiagnosticProperties.isEnabled())) {
68+
if (!shouldUseDetailedCacheInstrumentation(shouldRecord)) {
6969
PublicKey cachedKey = keyCache.getIfPresent(kid);
7070
if (cachedKey != null) {
7171
return cachedKey;
7272
}
7373
return keyCache.get(kid, this::resolvePublicKey);
7474
}
75+
PublicKey cachedKey = getCachedKey(kid, shouldRecord);
76+
if (cachedKey != null) {
77+
recordCacheHit(shouldRecord);
78+
return cachedKey;
79+
}
80+
81+
return loadMissPath(kid, shouldRecord);
82+
}
83+
84+
private void recordCacheObservation(String metricName, boolean shouldRecord) {
85+
if (!(shouldRecord && spikeDiagnosticProperties.isDetailedSummaryEnabled(metricName))) {
86+
return;
87+
}
88+
spikeApplyMetricRecorder.recordSummary(
89+
metricName,
90+
SpikeApplyRuntimeConfig.currentTxMode(),
91+
SpikeApplyRuntimeConfig.currentGate(),
92+
OUTCOME_OBSERVED,
93+
1.0
94+
);
95+
}
96+
97+
private void recordTimer(String metricName, long durationNanos, String outcome, boolean shouldRecord) {
98+
if (!(shouldRecord && spikeDiagnosticProperties.isDetailedTimerEnabled(metricName))) {
99+
return;
100+
}
101+
spikeApplyMetricRecorder.recordTimer(
102+
metricName,
103+
SpikeApplyRuntimeConfig.currentTxMode(),
104+
SpikeApplyRuntimeConfig.currentGate(),
105+
outcome,
106+
durationNanos
107+
);
108+
}
109+
110+
private boolean isSpikeApplyActive() {
111+
return "true".equals(MDC.get(MDC_ACTIVE_KEY)) && spikeDiagnosticProperties.isEnabled();
112+
}
113+
114+
private PublicKey getCachedKey(String kid, boolean shouldRecord) {
115+
if (!spikeDiagnosticProperties.isDetailedTimerEnabled(
116+
METRIC_JWT_GET_PUBLIC_KEY_CACHE_GET_IF_PRESENT_TOTAL)) {
117+
return keyCache.getIfPresent(kid);
118+
}
75119
long cacheLookupStart = System.nanoTime();
76120
String cacheLookupOutcome = OUTCOME_SUCCESS;
77-
PublicKey cachedKey;
78121
try {
79-
cachedKey = keyCache.getIfPresent(kid);
122+
return keyCache.getIfPresent(kid);
80123
} catch (RuntimeException exception) {
81124
cacheLookupOutcome = OUTCOME_ERROR;
82125
throw exception;
@@ -88,25 +131,35 @@ public PublicKey getPublicKey(String kid) {
88131
shouldRecord
89132
);
90133
}
91-
if (cachedKey != null) {
92-
long hitBookkeepingStart = System.nanoTime();
93-
String hitBookkeepingOutcome = OUTCOME_SUCCESS;
94-
try {
95-
recordCacheObservation(METRIC_JWK_CACHE_HIT, shouldRecord);
96-
return cachedKey;
97-
} catch (RuntimeException exception) {
98-
hitBookkeepingOutcome = OUTCOME_ERROR;
99-
throw exception;
100-
} finally {
101-
recordTimer(
102-
METRIC_JWT_GET_PUBLIC_KEY_HIT_BOOKKEEPING_TOTAL,
103-
System.nanoTime() - hitBookkeepingStart,
104-
hitBookkeepingOutcome,
105-
shouldRecord
106-
);
107-
}
134+
}
135+
136+
private void recordCacheHit(boolean shouldRecord) {
137+
if (!spikeDiagnosticProperties.isDetailedTimerEnabled(
138+
METRIC_JWT_GET_PUBLIC_KEY_HIT_BOOKKEEPING_TOTAL)) {
139+
recordCacheObservation(METRIC_JWK_CACHE_HIT, shouldRecord);
140+
return;
141+
}
142+
long hitBookkeepingStart = System.nanoTime();
143+
String hitBookkeepingOutcome = OUTCOME_SUCCESS;
144+
try {
145+
recordCacheObservation(METRIC_JWK_CACHE_HIT, shouldRecord);
146+
} catch (RuntimeException exception) {
147+
hitBookkeepingOutcome = OUTCOME_ERROR;
148+
throw exception;
149+
} finally {
150+
recordTimer(
151+
METRIC_JWT_GET_PUBLIC_KEY_HIT_BOOKKEEPING_TOTAL,
152+
System.nanoTime() - hitBookkeepingStart,
153+
hitBookkeepingOutcome,
154+
shouldRecord
155+
);
108156
}
157+
}
109158

159+
private PublicKey loadMissPath(String kid, boolean shouldRecord) {
160+
if (!spikeDiagnosticProperties.isDetailedTimerEnabled(METRIC_JWT_GET_PUBLIC_KEY_MISS_LOAD_TOTAL)) {
161+
return keyCache.get(kid, this::resolvePublicKey);
162+
}
110163
long missLoadStart = System.nanoTime();
111164
String missLoadOutcome = OUTCOME_SUCCESS;
112165
try {
@@ -124,36 +177,18 @@ public PublicKey getPublicKey(String kid) {
124177
}
125178
}
126179

127-
private void recordCacheObservation(String metricName, boolean shouldRecord) {
128-
if (!shouldRecord) {
129-
return;
130-
}
131-
spikeApplyMetricRecorder.recordSummary(
132-
metricName,
133-
SpikeApplyRuntimeConfig.currentTxMode(),
134-
SpikeApplyRuntimeConfig.currentGate(),
135-
OUTCOME_OBSERVED,
136-
1.0
137-
);
138-
}
139-
140-
private void recordTimer(String metricName, long durationNanos, String outcome, boolean shouldRecord) {
141-
if (!shouldRecord) {
142-
return;
143-
}
144-
spikeApplyMetricRecorder.recordTimer(
145-
metricName,
146-
SpikeApplyRuntimeConfig.currentTxMode(),
147-
SpikeApplyRuntimeConfig.currentGate(),
148-
outcome,
149-
durationNanos
180+
private boolean shouldUseDetailedCacheInstrumentation(boolean shouldRecord) {
181+
return shouldRecord
182+
&& spikeDiagnosticProperties.isEnabled()
183+
&& (
184+
spikeDiagnosticProperties.isDetailedTimerEnabled(METRIC_JWT_GET_PUBLIC_KEY_CACHE_GET_IF_PRESENT_TOTAL)
185+
|| spikeDiagnosticProperties.isDetailedTimerEnabled(METRIC_JWT_GET_PUBLIC_KEY_HIT_BOOKKEEPING_TOTAL)
186+
|| spikeDiagnosticProperties.isDetailedTimerEnabled(METRIC_JWT_GET_PUBLIC_KEY_MISS_LOAD_TOTAL)
187+
|| spikeDiagnosticProperties.isDetailedSummaryEnabled(METRIC_JWK_CACHE_HIT)
188+
|| spikeDiagnosticProperties.isDetailedSummaryEnabled(METRIC_JWK_CACHE_MISS)
150189
);
151190
}
152191

153-
private boolean isSpikeApplyActive() {
154-
return "true".equals(MDC.get(MDC_ACTIVE_KEY)) && spikeDiagnosticProperties.isEnabled();
155-
}
156-
157192
private PublicKey resolvePublicKey(String kid) {
158193
recordCacheObservation(METRIC_JWK_CACHE_MISS, isSpikeApplyActive());
159194
try {

main/src/main/java/org/sopt/makers/crew/main/global/metrics/SpikeApplyMetrics.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public final class SpikeApplyMetrics {
1616

1717
public static final String METRIC_APP_EDGE_TOTAL = "crew.spike.apply.envelope.app_edge.total";
1818
public static final String METRIC_APP_EDGE_PRE_REQUEST_TOTAL = "crew.spike.apply.envelope.app_edge.pre_request.total";
19+
public static final String METRIC_MDC_TOTAL = "crew.spike.apply.envelope.mdc.total";
1920
public static final String METRIC_REQUEST_TOTAL = "crew.spike.apply.envelope.request.total";
2021
public static final String METRIC_AUTH_TOTAL = "crew.spike.apply.envelope.auth.total";
2122
public static final String METRIC_JWT_VERIFY_TOTAL = "crew.spike.apply.envelope.jwt.verify.total";

main/src/main/java/org/sopt/makers/crew/main/global/metrics/SpikeDiagnosticProperties.java

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
package org.sopt.makers.crew.main.global.metrics;
22

3+
import java.util.ArrayList;
4+
import java.util.List;
5+
36
import org.springframework.boot.context.properties.ConfigurationProperties;
47

58
@ConfigurationProperties(prefix = "spike.diagnostic")
69
public class SpikeDiagnosticProperties {
710
private boolean enabled = true;
11+
private final Selective selective = new Selective();
812

913
public boolean isEnabled() {
1014
return enabled;
@@ -13,4 +17,51 @@ public boolean isEnabled() {
1317
public void setEnabled(boolean enabled) {
1418
this.enabled = enabled;
1519
}
20+
21+
public Selective getSelective() {
22+
return selective;
23+
}
24+
25+
public boolean isSelectiveEnabled() {
26+
return enabled && selective.enabled
27+
&& (!selective.timerAllowlist.isEmpty() || !selective.summaryAllowlist.isEmpty());
28+
}
29+
30+
public boolean isDetailedTimerEnabled(String metricName) {
31+
return enabled && (!isSelectiveEnabled() || selective.timerAllowlist.contains(metricName));
32+
}
33+
34+
public boolean isDetailedSummaryEnabled(String metricName) {
35+
return enabled && (!isSelectiveEnabled() || selective.summaryAllowlist.contains(metricName));
36+
}
37+
38+
public static class Selective {
39+
private boolean enabled;
40+
private List<String> timerAllowlist = new ArrayList<>();
41+
private List<String> summaryAllowlist = new ArrayList<>();
42+
43+
public boolean isEnabled() {
44+
return enabled;
45+
}
46+
47+
public void setEnabled(boolean enabled) {
48+
this.enabled = enabled;
49+
}
50+
51+
public List<String> getTimerAllowlist() {
52+
return timerAllowlist;
53+
}
54+
55+
public void setTimerAllowlist(List<String> timerAllowlist) {
56+
this.timerAllowlist = timerAllowlist != null ? new ArrayList<>(timerAllowlist) : new ArrayList<>();
57+
}
58+
59+
public List<String> getSummaryAllowlist() {
60+
return summaryAllowlist;
61+
}
62+
63+
public void setSummaryAllowlist(List<String> summaryAllowlist) {
64+
this.summaryAllowlist = summaryAllowlist != null ? new ArrayList<>(summaryAllowlist) : new ArrayList<>();
65+
}
66+
}
1667
}

0 commit comments

Comments
 (0)