AppLogger
is a React Native mobile application framework that helps in minimizing QA issue-reporting time and developer debugging time by providing a web interface for the logs generated and steps taken by the user on a device using the device's IP address. The user can keep track of their sessions and logs, as well as upload, download, and delete them.
Whenever an issue is reported, developers need issue reproducible steps along with some data to understand, debug and fix it. A lot of time, finding out these reproducible steps becomes a time-consuming effort.
QA data isn't always accurate for replicating the problem, and incomplete data can complicate troubleshooting. As a result, debugging time increases, and the issue may go unresolved since it is not reproducible.
To solve these problems, we need to track the user actions and application state and allow them to be shared easily.
AppLogger
provides React Native components with customized tracking to minimize the integration effort in any existing or a new application. It also provides a generic wrapper that can be used with any React Native component. A simple track
function can be used by developers to provide tracking logic to custom methods.
Developers can access the app sessions including the steps and associated logs via the web interface using the device's IP address. The web interface includes a session dashboard with a list of sessions and a session details page that includes device information as well as user action and developer logs.
AppLogger
proves to be a boon by eliminating the need to perform same steps manually for a number of times. Additionally, it simplifies the process to convey the bug's replication steps to developers.
It saves their time by keeping track of the steps in case of Random testing even when the issues are not reproducible.
- Session management - from the helper menu, the user can stop the current session, start a new one, and can temporarily disable tracking in the current session.
- Download Logs - session logs can be downloaded in HTML or JSON format from the web interface.
- Upload Logs - helper menu allows tracked session logs to be uploaded on any third party services. To use this feature, you must implement the upload function.
- Delete Logs - from the helper menu user can delete session logs.
Important Note: The Web Server would work only in a LAN connection i.e. both devices (one on which application is running, other on which web interface is being accessed) should be on the same network. Also, the application must be running in foreground.
We have provided a sample app for implementation reference and a quick sneak-peek.
npm install @truesparrow/applogger --save
AppLogger
has some peer dependencies. It is recommended that you follow the installation instructions of each package to verify that it is properly configured.
- @react-native-async-storage/async-storage
- react-native-device-info
- react-native-fs
- react-native-get-random-values
- react-native-http-bridge
- react-native-network-info
- react-native-shake
- react-native-exit-app
- react-native-exception-handler
npm install @react-native-async-storage/async-storage react-native-device-info react-native-fs react-native-get-random-values react-native-http-bridge react-native-network-info react-native-shake react-native-exit-app react-native-exception-handler
Navigate to your ios folder and run:
cd ios
pod install
To get started, you'll need to call the useAppLogger
hook in your project's root file. This hook allows you to start and stop the web server, which is necessary for viewing the logs.
useAppLogger
hook requires a prop of type AppLoggerParams
as mentioned below.
type AppLoggerParams = {
port?: number;
loggerConfig?: LogTrackerConfigInterface;
};
port
is an optional prop on which the server should start, default port is 5561
.
loggerConfig
is an object of type LogTrackerConfigInterface
. It's used to configure AppLogger
. If not provided, it will use default configuration.
interface LogTrackerConfigInterface {
writeFrequencyInSeconds: number;
uploadLogs?: (
sessionLogFilePaths: string[],
onUploadComplete: Function,
) => Promise<boolean>;
clearStorageOnLogUpload: boolean;
isTrackingDisabled?: boolean;
logRotateDurationInHours?: number;
sensitiveDataKeywords?: string[];
}
We can configure the following parameters:
writeFrequencyInSeconds
- frequency in which logs should be written in storage, default value is5
.uploadLogs
- Function to upload the logs to any third party storage serivce like s3. Upload will not work unless developer provides a function for it.clearStorageOnLogUpload
- Boolean to clear the storage when logs are uploaded.isTrackingDisabled
- Flag to disable log tracking. Default values - for production env : true, for dev env : false.logRotateDurationInHours
- Flag to clear the logs after certain intervals. If not provided, it will not automatically clear the logs from storage.sensitiveDataKeywords
- Array containing sensitive keys which when encountered in params will be redacted.
Here is a code snippet to configure AppLogger
on port 8000.
import {useAppLogger, HelperMenu} from '@truesparrow/AppLogger';
function App() {
const uploadFile = filePath => {
return new Promise((resolve, reject) => {
s3.upload(filePath)
.then(() => {
resolve(true);
})
.catch(() => {
reject();
});
});
};
const uploaderFunction = (sessionLogFilePaths, onLogUploadComplete) => {
return new Promise(resolve => {
sessionLogFilePaths.forEach((singleSessionLogFilePath, index) => {
uploadFile(singleSessionLogFilePath).then(() => {
if (index == sessionLogFilePaths.length - 1) {
// Call this function to delete log files from local app storage
onLogUploadComplete();
return resolve(true);
}
});
});
});
};
const AppLoggerParams = {
port: 8000,
loggerConfig: {
writeFrequencyInSeconds: 5,
uploadLogs: uploaderFunction,
clearStorageOnLogUpload: false,
isTrackingDisabled: false,
logRotateDurationInHours: 24,
sensitiveDataKeywords: ['password'],
},
};
const {navigationRef, onNavigationStateChange} =
useAppLogger(AppLoggerParams);
return (
<NavigationContainer
ref={navigationRef}
onStateChange={onNavigationStateChange}>
<RootNavigation />
<HelperMenu />
</NavigationContainer>
);
}
export default App;
The helper menu can now be accessed by shaking your device. This will enable you to do the following things:
- Share server URL.
- Upload logs.
- Delete Logs.
- Pause/resume current session.
- Stop current session and start a new session.
You can access your logs using the link below.
<your-ip-address>:<port>/session
For example:
192.168.0.1:8000/session
This link can be shared from the Share server URL
option in the helper menu.
Following are some of the React Native components that AppLogger provides with tracking.
- Button
- Pressable
- RefreshControl
- Switch
- TextInput
- TouchableHighlight
- TouchableOpacity
- TouchableWithoutFeedback
How to use these components? Just import these components from @truesparrow/AppLogger
instead of react-native
and provide a testID.
Eg - To import TouchableWithoutFeedback :
import {TouchableWithoutFeedback} from '@truesparrow/AppLogger';
<TouchableWithoutFeedback testID={'some_test_id'} />;
- The generic component from
AppLogger
can be used to enable tracking for any component other than those listed above.- The only additional step would be that to wrap the component (or list of components) in a
ComponentWrapper
and provide atestID
to those components. Apart from that, the wrapped components' logic stays unchanged.
- The only additional step would be that to wrap the component (or list of components) in a
- As it supports all
ViewProps
, theComponentWrapper
can be used in place of theView
Component. - As of now
ComponentWrapper
works only on a single level, which means it does not track action on children components of wrapped components.
Example snippets:
import {ComponentWrapper} from ‘@truesparrow/AppLogger’;
<ComponentWrapper>
<Component testID="component_test_id" {...props}/>
</ComponentWrapper>
import {ComponentWrapper} from ‘@truesparrow/AppLogger’;
<ComponentWrapper>
<Component1 testID="component1_test_id" {...props} />
<Component2 testID="component2_test_id" {...props} />
<Component3 testID="component3_test_id" {...props} />
</ComponentWrapper>
Following are the functions that have log tracking enabled in them.
- onChange
- onPress
- onLongPress
- onPressIn
- onPressOut
- onChangeText
- onContentSizeChange
- onEndEditing
- onFocus
- onKeyPress
- onLayout
- onScroll
- onSelectionChange
- onSubmitEditing
- onRefresh
- onValueChange
How to use these functions? No change, you can write it as you would normally do and the AppLogger
will take care of the rest, provided your component is imported from @truesparrow/AppLogger
or wrapped inside ComponentWrapper
.
You can use tracking for any other function that you choose, in addition to the ones listed above. AppLogger
provides a track interface for custom tracking of activity. Here type
and params
are mandatory, while other fields are optional.
interface TrackInterface {
id?: string;
description?: string;
type: string;
params: any;
ts?: number;
}
Here is an example for custom tracking using AppLogger
. Consider keeping track of any error that occurs when loading the image. It's implementation could be as follows.
import {useCallback} from 'react';
import {Image} from 'react-native';
import {getLogTracker} from '@truesparrow/AppLogger';
function CustomTrackingDemo() {
const imageTestID = 'custom_tracking_demo_image';
const fnOnError = useCallback((error) => {
const logTracker = getLogTracker();
logTracker.track({
description: `Encountered error on image load ${error}`,
type: 'ImageLoadError',
params: {
testId: imageTestID,
},
},
});
}, []);
return <Image src="image_url" testID={imageTestID} onError={fnOnError} />
}
AppLogger
is an open source project and will always remain free to use. Feel free to report issues, raise PRs for fixes & enhancements. If you think it's cool, please star it 🌟
Made with ❤️ at True Sparrow