Skip to content

Commit 81d74d8

Browse files
Merge duplicated error log entries into one (#11434)
When a MirrorEvmTransactionException is thrown, currently there are 2 log entries for 1 transaction and this makes the investigation harder as you need to find both entries and match them. The first entry contained the request body input and the second entry contained the resulting error output. With this PR both log entries are now merged into one. If the length of the log gets bigger than the maxPayloadLogSize property, it gets encoded as it did before for the input data. Also, the empty components in the error message are now removed and added to the log only if they are not empty. --------- Signed-off-by: Bilyana Gospodinova <[email protected]>
1 parent 5572e76 commit 81d74d8

File tree

5 files changed

+131
-9
lines changed

5 files changed

+131
-9
lines changed

docs/configuration.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -732,7 +732,7 @@ value, it is recommended to only populate overridden properties in the custom `a
732732
| `hiero.mirror.web3.evm.trace.status` | [] | A set with frame statuses to filter. By default it is empty to indicate it will trace all frames regardless of status. |
733733
| `hiero.mirror.web3.evm.modularizedTrafficPercent` | 0.0 | Indicates the probability of processing a transaction through the transaction execution service, instead of the mirrorEvmTxProcessor. |
734734
| `hiero.mirror.web3.evm.entityNumBuffer` | 1000 | A buffer added to the max known entity number to prevent contract call simulations from generating IDs that may conflict with entities persisted by the importer module. |
735-
| `hiero.mirror.web3.maxPayloadLogSize` | 300 | The maximum number of bytes to use to log the request payload. |
735+
| `hiero.mirror.web3.maxPayloadLogSize` | 300 | The maximum number of characters to use to log the request payload. |
736736
| `hiero.mirror.web3.opcode.tracer.enabled` | false | Whether the `/contracts/results/{transactionIdOrHash}/opcodes` endpoint is exposed |
737737
| `hiero.mirror.web3.requestTimeout` | 10000 | The maximum amount of time to wait for a request to process. |
738738
| `hiero.mirror.web3.throttle.gasLimitRefundPercent` | 100 | Maximum gas percent from the passed gas limit in a request to return in the throttle bucket after the request is processed |

web3/src/main/java/org/hiero/mirror/web3/config/LoggingFilter.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import lombok.RequiredArgsConstructor;
1818
import org.apache.commons.lang3.StringUtils;
1919
import org.hiero.mirror.web3.Web3Properties;
20+
import org.hiero.mirror.web3.exception.MirrorEvmTransactionException;
2021
import org.springframework.http.HttpStatus;
2122
import org.springframework.web.filter.OncePerRequestFilter;
2223
import org.springframework.web.util.ContentCachingRequestWrapper;
@@ -114,6 +115,9 @@ private String getMessage(HttpServletRequest request, Exception e) {
114115
}
115116

116117
if (request.getAttribute(ERROR_EXCEPTION_ATTRIBUTE) instanceof Exception ex) {
118+
if (ex instanceof MirrorEvmTransactionException mirrorEvmTransactionException) {
119+
return mirrorEvmTransactionException.getFullMessage();
120+
}
117121
return ex.getMessage();
118122
}
119123

web3/src/main/java/org/hiero/mirror/web3/controller/GenericControllerAdvice.java

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,8 @@ private ResponseEntity<?> badRequest(final Exception e, final WebRequest request
7272
}
7373

7474
@ExceptionHandler
75-
private ResponseEntity<?> mirrorEvmTransactionError(final MirrorEvmTransactionException e, WebRequest request) {
76-
log.warn(
77-
"Mirror EVM transaction error: {}, detail: {}, data: {}, isModularized: {}, childTransactionErrors: {}",
78-
e.getMessage(),
79-
e.getDetail(),
80-
e.getData(),
81-
e.getIsCallModularized(),
82-
e.getChildTransactionErrors());
75+
private ResponseEntity<?> mirrorEvmTransactionError(
76+
final MirrorEvmTransactionException e, final WebRequest request) {
8377
request.setAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE, e, SCOPE_REQUEST);
8478
final var childTransactionErrors = e.getChildTransactionErrors().stream()
8579
.map(message -> new ErrorMessage(message, StringUtils.EMPTY, StringUtils.EMPTY))

web3/src/main/java/org/hiero/mirror/web3/exception/MirrorEvmTransactionException.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,19 @@ public Bytes messageBytes() {
7878
return Bytes.of(message.getBytes(StandardCharsets.UTF_8));
7979
}
8080

81+
public String getFullMessage() {
82+
final var exceptionMessageBuilder =
83+
new StringBuilder().append("Mirror EVM transaction error: ").append(getMessage());
84+
if (!StringUtils.isBlank(getDetail())) {
85+
exceptionMessageBuilder.append(", detail: ").append(getDetail());
86+
}
87+
if (getChildTransactionErrors() != null && !getChildTransactionErrors().isEmpty()) {
88+
exceptionMessageBuilder.append(", childTransactionErrors: ").append(getChildTransactionErrors());
89+
}
90+
exceptionMessageBuilder.append(", data: ").append(getData());
91+
return exceptionMessageBuilder.toString();
92+
}
93+
8194
@Override
8295
public String toString() {
8396
return "%s(message=%s, detail=%s, data=%s, dataDecoded=%s)"

web3/src/test/java/org/hiero/mirror/web3/config/LoggingFilterTest.java

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,22 @@
55
import static com.google.common.net.HttpHeaders.X_FORWARDED_FOR;
66
import static org.assertj.core.api.Assertions.assertThat;
77
import static org.hiero.mirror.web3.utils.Constants.MODULARIZED_HEADER;
8+
import static org.springframework.web.util.WebUtils.ERROR_EXCEPTION_ATTRIBUTE;
89

10+
import com.hederahashgraph.api.proto.java.ResponseCodeEnum;
911
import java.nio.charset.StandardCharsets;
12+
import java.util.LinkedList;
13+
import java.util.List;
1014
import lombok.SneakyThrows;
1115
import org.apache.commons.io.IOUtils;
1216
import org.apache.commons.lang3.RandomStringUtils;
1317
import org.apache.commons.lang3.StringUtils;
1418
import org.hiero.mirror.web3.Web3Properties;
19+
import org.hiero.mirror.web3.exception.MirrorEvmTransactionException;
1520
import org.junit.jupiter.api.Test;
1621
import org.junit.jupiter.api.extension.ExtendWith;
22+
import org.junit.jupiter.params.ParameterizedTest;
23+
import org.junit.jupiter.params.provider.NullAndEmptySource;
1724
import org.springframework.boot.test.system.CapturedOutput;
1825
import org.springframework.boot.test.system.OutputCaptureExtension;
1926
import org.springframework.http.HttpStatus;
@@ -154,6 +161,110 @@ void postLargeUncompressibleContent(CapturedOutput output) {
154161
assertThat(output.getOut()).contains(content.substring(0, maxSize)).doesNotContain(content);
155162
}
156163

164+
@Test
165+
@SneakyThrows
166+
void getFullExceptionMessage(CapturedOutput output) {
167+
int maxSize = web3Properties.getMaxPayloadLogSize();
168+
var content = "abcdef0123456789";
169+
var request = new MockHttpServletRequest("POST", "/");
170+
request.setContent(content.getBytes(StandardCharsets.UTF_8));
171+
request.setAttribute(
172+
ERROR_EXCEPTION_ATTRIBUTE,
173+
new MirrorEvmTransactionException(
174+
ResponseCodeEnum.CONTRACT_REVERT_EXECUTED.name(),
175+
"detail",
176+
"0123456",
177+
null,
178+
true,
179+
List.of("childMessage")));
180+
response.setStatus(HttpStatus.OK.value());
181+
182+
loggingFilter.doFilter(request, response, (req, res) -> IOUtils.toString(req.getReader()));
183+
184+
assertThat(output.getOut())
185+
.contains(
186+
"Mirror EVM transaction error: CONTRACT_REVERT_EXECUTED, detail: detail, childTransactionErrors: [childMessage], data: 0123456 - abcdef0123456789");
187+
}
188+
189+
@ParameterizedTest
190+
@NullAndEmptySource
191+
@SneakyThrows
192+
void getFullExceptionMessageDetailEmpty(final String detail, CapturedOutput output) {
193+
int maxSize = web3Properties.getMaxPayloadLogSize();
194+
var content = "abcdef0123456789";
195+
var request = new MockHttpServletRequest("POST", "/");
196+
request.setContent(content.getBytes(StandardCharsets.UTF_8));
197+
request.setAttribute(
198+
ERROR_EXCEPTION_ATTRIBUTE,
199+
new MirrorEvmTransactionException(
200+
ResponseCodeEnum.CONTRACT_REVERT_EXECUTED.name(),
201+
detail,
202+
"0123456",
203+
null,
204+
true,
205+
List.of("childMessage")));
206+
response.setStatus(HttpStatus.OK.value());
207+
208+
loggingFilter.doFilter(request, response, (req, res) -> IOUtils.toString(req.getReader()));
209+
210+
assertThat(output.getOut())
211+
.contains(
212+
"Mirror EVM transaction error: CONTRACT_REVERT_EXECUTED, childTransactionErrors: [childMessage], data: 0123456 - abcdef0123456789");
213+
}
214+
215+
@ParameterizedTest
216+
@NullAndEmptySource
217+
@SneakyThrows
218+
void getFullExceptionMessageChildErrorsEmpty(final LinkedList<String> childErrors, CapturedOutput output) {
219+
int maxSize = web3Properties.getMaxPayloadLogSize();
220+
var content = "abcdef0123456789";
221+
var request = new MockHttpServletRequest("POST", "/");
222+
request.setContent(content.getBytes(StandardCharsets.UTF_8));
223+
request.setAttribute(
224+
ERROR_EXCEPTION_ATTRIBUTE,
225+
new MirrorEvmTransactionException(
226+
ResponseCodeEnum.CONTRACT_REVERT_EXECUTED.name(),
227+
"detail",
228+
"0123456",
229+
null,
230+
true,
231+
childErrors));
232+
response.setStatus(HttpStatus.OK.value());
233+
234+
loggingFilter.doFilter(request, response, (req, res) -> IOUtils.toString(req.getReader()));
235+
236+
assertThat(output.getOut())
237+
.contains(
238+
"Mirror EVM transaction error: CONTRACT_REVERT_EXECUTED, detail: detail, data: 0123456 - abcdef0123456789");
239+
}
240+
241+
@Test
242+
@SneakyThrows
243+
void getFullExceptionMessageWithCompressedContent(CapturedOutput output) {
244+
int maxSize = web3Properties.getMaxPayloadLogSize();
245+
var content = StringUtils.repeat("abcdefghij", maxSize / 10 + 1);
246+
var request = new MockHttpServletRequest("POST", "/");
247+
request.setContent(content.getBytes(StandardCharsets.UTF_8));
248+
request.setAttribute(
249+
ERROR_EXCEPTION_ATTRIBUTE,
250+
new MirrorEvmTransactionException(
251+
ResponseCodeEnum.CONTRACT_REVERT_EXECUTED.name(),
252+
"detail",
253+
"0123456",
254+
null,
255+
true,
256+
List.of("childMessage")));
257+
response.setStatus(HttpStatus.OK.value());
258+
259+
loggingFilter.doFilter(request, response, (req, res) -> IOUtils.toString(req.getReader()));
260+
261+
var compressed = "H4sIAAAAAAAA/0tMSk5JTUvPyMxKHGURzQIAy81t7zYBAAA=";
262+
assertThat(output.getOut())
263+
.contains(
264+
"Mirror EVM transaction error: CONTRACT_REVERT_EXECUTED, detail: detail, childTransactionErrors: [childMessage], data: 0123456 - "
265+
+ compressed);
266+
}
267+
157268
private void assertLog(CapturedOutput logOutput, String level, String pattern) {
158269
assertThat(logOutput).asString().hasLineCount(1).contains(level).containsPattern(pattern);
159270
}

0 commit comments

Comments
 (0)