Skip to content

Commit f79d161

Browse files
committed
[#9200] Backport: Fix agent callstack overflow log
1 parent a1ef196 commit f79d161

File tree

27 files changed

+307
-33
lines changed

27 files changed

+307
-33
lines changed

agent/src/main/resources/profiles/local/pinpoint.config

+1
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ profiler.monitor.deadlock.interval=60000
165165
## Call Stack
166166
# Set max depth, if -1 is unlimited and min is 2.
167167
profiler.callstack.max.depth=64
168+
profiler.callstack.overflow.log.ration=100
168169

169170
# weather or not to propagate exceptions occurred at interceptor
170171
profiler.interceptor.exception.propagate=false

agent/src/main/resources/profiles/release/pinpoint.config

+1
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ profiler.monitor.deadlock.interval=60000
165165
## Call Stack
166166
# Set max depth, if -1 is unlimited and min is 2.
167167
profiler.callstack.max.depth=64
168+
profiler.callstack.overflow.log.ration=100
168169

169170
# weather or not to propagate exceptions occurred at interceptor
170171
profiler.interceptor.exception.propagate=false

bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/AsyncContextSpanEventEndPointInterceptor.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,8 @@ protected AsyncContext getAsyncContext(Object target, Object[] args) {
143143
private Trace getAsyncTrace(AsyncContext asyncContext) {
144144
final Trace trace = asyncContext.continueAsyncTraceObject();
145145
if (trace == null) {
146-
if (logger.isWarnEnabled()) {
147-
logger.warn("Failed to continue async trace. 'result is null'");
146+
if (isDebug) {
147+
logger.debug("Failed to continue async trace. 'result is null'");
148148
}
149149
return null;
150150
}

bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/AsyncContextSpanEventSimpleAroundInterceptor.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,8 @@ protected AsyncContext getAsyncContext(Object target, Object[] args, Object resu
127127
private Trace getAsyncTrace(AsyncContext asyncContext) {
128128
final Trace trace = asyncContext.continueAsyncTraceObject();
129129
if (trace == null) {
130-
if (logger.isWarnEnabled()) {
131-
logger.warn("Failed to continue async trace. 'result is null'");
130+
if (isDebug) {
131+
logger.debug("Failed to continue async trace. 'result is null'");
132132
}
133133
return null;
134134
}

plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/interceptor/AsyncContextSpanEventEndPointInterceptor.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,8 @@ protected AsyncContext getAsyncContext(Object target) {
145145
private Trace getAsyncTrace(AsyncContext asyncContext) {
146146
final Trace trace = asyncContext.continueAsyncTraceObject();
147147
if (trace == null) {
148-
if (logger.isWarnEnabled()) {
149-
logger.warn("Failed to continue async trace. 'result is null'");
148+
if (isDebug) {
149+
logger.debug("Failed to continue async trace. 'result is null'");
150150
}
151151
return null;
152152
}

plugins/netty/src/main/java/com/navercorp/pinpoint/plugin/netty/interceptor/http/HttpEncoderInterceptor.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -232,8 +232,8 @@ protected void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[
232232
private Trace getAsyncTrace(AsyncContext asyncContext) {
233233
final Trace trace = asyncContext.continueAsyncTraceObject();
234234
if (trace == null) {
235-
if (logger.isWarnEnabled()) {
236-
logger.warn("Failed to continue async trace. 'result is null'");
235+
if (isDebug) {
236+
logger.debug("Failed to continue async trace. 'result is null'");
237237
}
238238
return null;
239239
}

plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/interceptor/ConsumerHandleDeliveryInterceptor.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,8 @@ private boolean validate(Object target, Object[] args) {
134134
private Trace getAsyncTrace(AsyncContext asyncContext) {
135135
final Trace trace = asyncContext.continueAsyncTraceObject();
136136
if (trace == null) {
137-
if (logger.isWarnEnabled()) {
138-
logger.warn("Failed to continue async trace. 'result is null'");
137+
if (isDebug) {
138+
logger.debug("Failed to continue async trace. 'result is null'");
139139
}
140140
return null;
141141
}

plugins/user/src/main/java/com/navercorp/pinpoint/plugin/user/interceptor/MQExternalClientHandlerInterceptor.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,8 @@ private AsyncContext getAsyncContext(Object[] args) {
136136
private Trace getAsyncTrace(AsyncContext asyncContext) {
137137
final Trace trace = asyncContext.continueAsyncTraceObject();
138138
if (trace == null) {
139-
if (logger.isWarnEnabled()) {
140-
logger.warn("Failed to continue async trace. 'result is null'");
139+
if (isDebug) {
140+
logger.debug("Failed to continue async trace. 'result is null'");
141141
}
142142
return null;
143143
}

plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/interceptor/AsyncContextSpanEventEndPointInterceptor.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,8 @@ protected AsyncContext getAsyncContext(Object target) {
145145
private Trace getAsyncTrace(AsyncContext asyncContext) {
146146
final Trace trace = asyncContext.continueAsyncTraceObject();
147147
if (trace == null) {
148-
if (logger.isWarnEnabled()) {
149-
logger.warn("Failed to continue async trace. 'result is null'");
148+
if (isDebug) {
149+
logger.debug("Failed to continue async trace. 'result is null'");
150150
}
151151
return null;
152152
}

profiler/src/main/java/com/navercorp/pinpoint/profiler/context/AsyncChildTrace.java

-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ public class AsyncChildTrace implements Trace {
3939

4040
private static final Logger logger = LogManager.getLogger(AsyncChildTrace.class.getName());
4141
private static final boolean isDebug = logger.isDebugEnabled();
42-
4342
private final CallStack<SpanEvent> callStack;
4443

4544
private final Storage storage;

profiler/src/main/java/com/navercorp/pinpoint/profiler/context/CallStack.java

+2
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ public interface CallStack<T> {
4040

4141
Factory<T> getFactory();
4242

43+
void setOverflowListener(CallStackOverflowListener overflowListener);
44+
4345
interface Factory<T> {
4446
Class<T> getType();
4547

profiler/src/main/java/com/navercorp/pinpoint/profiler/context/CallStackFactoryV1.java

+11-3
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,22 @@ public class CallStackFactoryV1 implements CallStackFactory<SpanEvent> {
2424
private final CallStack.Factory<SpanEvent> factory = new SpanEventFactory();
2525
private final int maxDepth;
2626
private final int maxSequence;
27+
private final CallStackOverflowListener overflowListener;
2728

28-
public CallStackFactoryV1(int maxDepth, int maxSequence) {
29+
public CallStackFactoryV1(int maxDepth, int maxSequence, int overflowLogRation) {
2930
this.maxDepth = maxDepth;
3031
this.maxSequence = maxSequence;
32+
if (overflowLogRation > 1) {
33+
this.overflowListener = new ThrottledLogCallStackOverflowListener(maxDepth, maxSequence, overflowLogRation);
34+
} else {
35+
this.overflowListener = new DefaultCallStackOverflowListener(maxDepth, maxSequence);
36+
}
3137
}
3238

3339
@Override
3440
public CallStack<SpanEvent> newCallStack() {
35-
return new DepthCompressCallStack<>(factory, maxDepth, maxSequence);
41+
final CallStack<SpanEvent> callStack = new DepthCompressCallStack<>(factory, maxDepth, maxSequence);
42+
callStack.setOverflowListener(overflowListener);
43+
return callStack;
3644
}
37-
}
45+
}

profiler/src/main/java/com/navercorp/pinpoint/profiler/context/CallStackFactoryV2.java

+10-2
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,22 @@ public class CallStackFactoryV2 implements CallStackFactory<SpanEvent> {
2424
private final CallStack.Factory<SpanEvent> factory = new SpanEventFactory();
2525
private final int maxDepth;
2626
private final int maxSequence;
27+
private final CallStackOverflowListener overflowListener;
2728

28-
public CallStackFactoryV2(int maxDepth, int maxSequence) {
29+
public CallStackFactoryV2(int maxDepth, int maxSequence, int overflowLogRation) {
2930
this.maxDepth = maxDepth;
3031
this.maxSequence = maxSequence;
32+
if (overflowLogRation > 1) {
33+
this.overflowListener = new ThrottledLogCallStackOverflowListener(maxDepth, maxSequence, overflowLogRation);
34+
} else {
35+
this.overflowListener = new DefaultCallStackOverflowListener(maxDepth, maxSequence);
36+
}
3137
}
3238

3339
@Override
3440
public CallStack<SpanEvent> newCallStack() {
35-
return new DefaultCallStack<>(factory, maxDepth, maxSequence);
41+
final CallStack<SpanEvent> callStack = new DefaultCallStack<>(factory, maxDepth, maxSequence);
42+
callStack.setOverflowListener(overflowListener);
43+
return callStack;
3644
}
3745
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright 2022 NAVER Corp.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.navercorp.pinpoint.profiler.context;
18+
19+
public interface CallStackOverflowListener {
20+
21+
void fireOverflow(int callStackIndex);
22+
}

profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultCallStack.java

+19-4
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ public class DefaultCallStack<T> implements CallStack<T> {
3939
protected int overflowIndex = 0;
4040
protected final int maxSequence;
4141
protected int sequence;
42+
protected CallStackOverflowListener overflowListener;
43+
protected boolean overflowed = false;
4244

4345
public DefaultCallStack(Factory<T> factory) {
4446
this(factory, -1, -1);
@@ -53,16 +55,28 @@ public DefaultCallStack(Factory<T> factory, int maxDepth, int maxSequence) {
5355
this.factory = factory;
5456
this.maxDepth = maxDepth;
5557
this.maxSequence = maxSequence;
56-
5758
this.stack = newStack(factory.getType(), STACK_SIZE);
5859
}
5960

61+
public void setOverflowListener(CallStackOverflowListener overflowListener) {
62+
this.overflowListener = overflowListener;
63+
}
64+
65+
void onOverflow(final int point) {
66+
if (Boolean.FALSE == overflowed) {
67+
if (overflowListener != null) {
68+
overflowListener.fireOverflow(point);
69+
}
70+
// Make sure it runs only once per CallStack.
71+
overflowed = true;
72+
}
73+
}
74+
6075
@SuppressWarnings("unchecked")
6176
private T[] newStack(Class<T> type, int size) {
6277
return (T[]) Array.newInstance(type, size);
6378
}
6479

65-
6680
@Override
6781
public int getIndex() {
6882
if (isOverflow()) {
@@ -76,7 +90,9 @@ public int getIndex() {
7690
public int push(final T element) {
7791
if (isOverflow()) {
7892
overflowIndex++;
79-
return index + overflowIndex;
93+
final int point = index + overflowIndex;
94+
onOverflow(point);
95+
return point;
8096
}
8197

8298
checkExtend(index + 1);
@@ -90,7 +106,6 @@ protected void markDepth(T element, int index) {
90106
factory.markDepth(element, index);
91107
}
92108

93-
94109
private void checkExtend(final int size) {
95110
final T[] originalStack = this.stack;
96111
if (size >= originalStack.length) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright 2022 NAVER Corp.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.navercorp.pinpoint.profiler.context;
18+
19+
import org.apache.logging.log4j.LogManager;
20+
import org.apache.logging.log4j.Logger;
21+
22+
public class DefaultCallStackOverflowListener implements CallStackOverflowListener {
23+
private final Logger logger = LogManager.getLogger(this.getClass());
24+
private final boolean isInfo = logger.isInfoEnabled();
25+
26+
private final int maxDepth;
27+
private final int maxSequence;
28+
29+
public DefaultCallStackOverflowListener(final int maxDepth, final int maxSequence) {
30+
this.maxDepth = maxDepth;
31+
this.maxSequence = maxSequence;
32+
}
33+
34+
@Override
35+
public void fireOverflow(final int callStackIndex) {
36+
if (isInfo) {
37+
logger.info("CallStack maximum depth/sequence exceeded. Check the profiler.callstack.max.depth. current.index={}, max.depth={}, max.sequence={}", callStackIndex, maxDepth, maxSequence);
38+
}
39+
}
40+
}

profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DepthCompressCallStack.java

-3
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,4 @@ protected void markDepth(T element, int depth) {
4343
this.factory.markDepth(element, latestStackIndex);
4444
}
4545
}
46-
47-
48-
4946
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright 2022 NAVER Corp.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.navercorp.pinpoint.profiler.context;
18+
19+
import com.navercorp.pinpoint.common.profiler.logging.ThrottledLogger;
20+
import org.apache.logging.log4j.LogManager;
21+
import org.apache.logging.log4j.Logger;
22+
23+
public class ThrottledLogCallStackOverflowListener implements CallStackOverflowListener {
24+
private final Logger logger = LogManager.getLogger(this.getClass());
25+
private final boolean isInfo = logger.isInfoEnabled();
26+
27+
private final int maxDepth;
28+
private final int maxSequence;
29+
private ThrottledLogger throttledLogger;
30+
31+
public ThrottledLogCallStackOverflowListener(final int maxDepth, final int maxSequence, final int overflowLogRation) {
32+
this.maxDepth = maxDepth;
33+
this.maxSequence = maxSequence;
34+
this.throttledLogger = ThrottledLogger.getLogger(logger, overflowLogRation);
35+
}
36+
37+
@Override
38+
public void fireOverflow(final int callStackIndex) {
39+
if (isInfo) {
40+
throttledLogger.info("CallStack maximum depth/sequence exceeded. Check the profiler.callstack.max.depth. current.index={}, max.depth={}, max.sequence={}", callStackIndex, maxDepth, maxSequence);
41+
}
42+
}
43+
}

profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/CallStackFactoryProvider.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -35,25 +35,25 @@ public class CallStackFactoryProvider implements Provider<CallStackFactory<SpanE
3535
private final TraceDataFormatVersion version;
3636
private final int callStackMaxDepth;
3737
private final int callStackMaxSequence;
38-
38+
private final int callStackOverflowLogRation;
3939

4040
@Inject
4141
public CallStackFactoryProvider(InstrumentConfig instrumentConfig,
4242
TraceDataFormatVersion version) {
4343
this.version = Objects.requireNonNull(version, "version");
4444
this.callStackMaxDepth = instrumentConfig.getCallStackMaxDepth();
4545
this.callStackMaxSequence = instrumentConfig.getCallStackMaxSequence();
46+
this.callStackOverflowLogRation = instrumentConfig.getCallStackOverflowLogRation();
4647
}
4748

4849
@Override
4950
public CallStackFactory<SpanEvent> get() {
5051
if (version == TraceDataFormatVersion.V2) {
51-
return new CallStackFactoryV2(callStackMaxDepth, callStackMaxSequence);
52+
return new CallStackFactoryV2(callStackMaxDepth, callStackMaxSequence, callStackOverflowLogRation);
5253
}
5354
if (version == TraceDataFormatVersion.V1) {
54-
return new CallStackFactoryV1(callStackMaxDepth, callStackMaxSequence);
55+
return new CallStackFactoryV1(callStackMaxDepth, callStackMaxSequence, callStackOverflowLogRation);
5556
}
5657
throw new UnsupportedOperationException("unknown version :" + version);
5758
}
58-
5959
}

0 commit comments

Comments
 (0)