From 49d26eb0c4aeb611c6cb37a568708afa67b48c18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Tue, 30 Apr 2019 07:30:45 -0700 Subject: [PATCH] cleanup RedBox message and stack output (#24662) Summary: Cleanup RedBox messages and stack traces. This PR consists of 2 changes (I'm good with splitting them up if you'd like): - [general] filter out some of the internal callsites from the symbolicated stack (I thought about using monospace font for title with code frame, but it looks weird) - [ios][android] strip ANSI characters (coming from colored Babel code frame) from the error message I think it's ok to strip it inside native handlers so we can still have a colorful code frame in the terminal output. **JS Code frame:** |before|after| |--|--| |Screenshot 2019-04-30 at 12 32 05|Screenshot 2019-04-30 at 12 52 43| |before|after| |--|--| |![image](https://user-images.githubusercontent.com/5106466/56959472-c8618980-6b4d-11e9-84be-6261d8375f4a.png)|![image](https://user-images.githubusercontent.com/5106466/56959463-bc75c780-6b4d-11e9-9d8b-25ffe46c87cf.png)| **Filtered stack traces:** |before|after| |--|--| |Screenshot 2019-04-30 at 12 27 21Screenshot 2019-04-30 at 12 27 28|Screenshot 2019-04-30 at 12 26 55| There's still a lot of places that are hard to read, but I think this is a good start towards more readable errors. cc cpojer [General][Changed] - Cleanup RedBox message and stack output Pull Request resolved: https://github.com/facebook/react-native/pull/24662 Differential Revision: D15147571 Pulled By: cpojer fbshipit-source-id: 1de4e521af988fa7fc709b6accd0ddd984388e72 --- Libraries/Core/ExceptionsManager.js | 12 ++++++++++- React/Modules/RCTRedBox.m | 20 ++++++++++++++----- .../react/devsupport/RedBoxDialog.java | 3 ++- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/Libraries/Core/ExceptionsManager.js b/Libraries/Core/ExceptionsManager.js index 08fe06f72b6..dfc41cd155a 100644 --- a/Libraries/Core/ExceptionsManager.js +++ b/Libraries/Core/ExceptionsManager.js @@ -12,6 +12,13 @@ import type {ExtendedError} from 'parseErrorStack'; +const INTERNAL_CALLSITES_REGEX = new RegExp( + [ + '/Libraries/Renderer/oss/ReactNativeRenderer-dev\\.js$', + '/Libraries/BatchedBridge/MessageQueue\\.js$', + ].join('|'), +); + /** * Handles the developer-visible aspect of errors and exceptions */ @@ -38,9 +45,12 @@ function reportException(e: ExtendedError, isFatal: boolean) { symbolicateStackTrace(stack) .then(prettyStack => { if (prettyStack) { + const stackWithoutInternalCallsites = prettyStack.filter( + frame => frame.file.match(INTERNAL_CALLSITES_REGEX) === null, + ); ExceptionsManager.updateExceptionMessage( e.message, - prettyStack, + stackWithoutInternalCallsites, currentExceptionID, ); } else { diff --git a/React/Modules/RCTRedBox.m b/React/Modules/RCTRedBox.m index d7c13065ee8..7ed4900d319 100644 --- a/React/Modules/RCTRedBox.m +++ b/React/Modules/RCTRedBox.m @@ -134,7 +134,7 @@ CGFloat buttonWidth = self.bounds.size.width / 4; CGFloat bottomButtonHeight = self.bounds.size.height - buttonHeight - [self bottomSafeViewHeight]; - + dismissButton.frame = CGRectMake(0, bottomButtonHeight, buttonWidth, buttonHeight); reloadButton.frame = CGRectMake(buttonWidth, bottomButtonHeight, buttonWidth, buttonHeight); copyButton.frame = CGRectMake(buttonWidth * 2, bottomButtonHeight, buttonWidth, buttonHeight); @@ -148,11 +148,11 @@ [rootView addSubview:copyButton]; [rootView addSubview:extraButton]; [rootView addSubview:topBorder]; - + UIView *bottomSafeView = [UIView new]; bottomSafeView.backgroundColor = [UIColor colorWithRed:0.1 green:0.1 blue:0.1 alpha:1]; bottomSafeView.frame = CGRectMake(0, self.bounds.size.height - [self bottomSafeViewHeight], self.bounds.size.width, [self bottomSafeViewHeight]); - + [rootView addSubview:bottomSafeView]; } return self; @@ -176,14 +176,24 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder) [[NSNotificationCenter defaultCenter] removeObserver:self]; } +- (NSString *)stripAnsi:(NSString *)text +{ + NSError *error = nil; + NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"\\x1b\\[[0-9;]*m" options:NSRegularExpressionCaseInsensitive error:&error]; + return [regex stringByReplacingMatchesInString:text options:0 range:NSMakeRange(0, [text length]) withTemplate:@""]; +} + - (void)showErrorMessage:(NSString *)message withStack:(NSArray *)stack isUpdate:(BOOL)isUpdate { + // Remove ANSI color codes from the message + NSString *messageWithoutAnsi = [self stripAnsi:message]; + // Show if this is a new message, or if we're updating the previous message - if ((self.hidden && !isUpdate) || (!self.hidden && isUpdate && [_lastErrorMessage isEqualToString:message])) { + if ((self.hidden && !isUpdate) || (!self.hidden && isUpdate && [_lastErrorMessage isEqualToString:messageWithoutAnsi])) { _lastStackTrace = stack; // message is displayed using UILabel, which is unable to render text of // unlimited length, so we truncate it - _lastErrorMessage = [message substringToIndex:MIN((NSUInteger)10000, message.length)]; + _lastErrorMessage = [messageWithoutAnsi substringToIndex:MIN((NSUInteger)10000, messageWithoutAnsi.length)]; [_stackTraceTableView reloadData]; diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/RedBoxDialog.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/RedBoxDialog.java index 361d27d3cef..14c0867bb49 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/RedBoxDialog.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/RedBoxDialog.java @@ -169,7 +169,8 @@ import org.json.JSONObject; ? (TextView) convertView : (TextView) LayoutInflater.from(parent.getContext()) .inflate(R.layout.redbox_item_title, parent, false); - title.setText(mTitle); + // Remove ANSI color codes from the title + title.setText(mTitle.replaceAll("\\x1b\\[[0-9;]*m", "")); return title; } else { if (convertView == null) {