Save your browser console logs to AWS CloudWatch (Inspired by agea/console-cloud-watch)
npm install @ibrightsider/cloudwatch-front-loggerSave your browser console logs to AWS CloudWatch (Inspired by agea/console-cloud-watch)
- Demo: mpyw/cloudwatch-front-logger-demo
```
npm i cloudwatch-front-logger
Go to CloudWatch console and create Log Group for this purpose.
Go to IAM Console and create restricted policy for CloudWatch Logs.
- logs:CreateLogStreamlogs:PutLogEvents
-
`json5`
{
"Version": "2019-12-08",
"Statement": [
{
"Sid": "CloudWatchFrontLoggerSid",
"Effect": "Allow",
"Action": [
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": [
"arn:aws:logs:::log-group:
"arn:aws:logs:::log-group:
]
}
]
}
Go to IAM Console and create user with the restricted policy.
`js
import { Logger } from 'cloudwatch-front-logger'
const accessKeyId = 'XXXXXXXXXXXXXXXXXXXX'
const secretAccessKey = 'YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY'
const region = 'ap-northeast-1'
const logGroupName = '
const logger = new Logger(accessKeyId, secretAccessKey, region, logGroupName)
logger.install()
`
Logs are collected from the following sources.
- Uncaught Error
- console.error() calllogger.onError()
- Manual call
(See integration examples)
By default, "anonymous" is used for logStreamName value.logStreamNameResolver
If you wish allocating a unique stream for each user, you can use a method such as Canvas Fingerprint.
Pass a resolver function as option value on install() call.
`js
import FingerprintJS from 'fingerprintjs'
logger.install({
async logStreamNameResolver() {
const fp = await FingerprintJS.load()
const { visitorId } = await fp.get()
return visitorId
},
})
`
By default, messages are formatted into JSON string which has message and type.
`json5`
{
"message": "Err: Something went wrong",
"type": "uncaught"
}
`json5`
{
"message": "Something went wrong",
"type": "console",
"level": "error"
}
If you wish formatting them by yourself, pass a formatter function as messageFormatter option value on install() call. Note that you can cancel by returning null from the fuunction.
`js
import StackTrace from 'stacktrace-js'
logger.install({
async messageFormatter(e, info = { type: 'unknown' }) {
if (!e.message) {
return null
}
let stack = null
if (e.stack) {
stack = e.stack
try {
stack = await StackTrace.fromError(e, { offline: true })
} catch (_) {
}
}
return JSON.stringify({
message: e.message,
timestamp: new Date().getTime(),
userAgent: window.navigator.userAgent,
stack,
...info,
})
},
})
`
By default, localStorage is used for caching logStreamName and nextSequenceToken.localStorage
Still has only synchronous API, asynchronous interfaces are also supported.localStorage
If you need to change storage implementation from , pass an instance as storage option value on install() call.
`js
import { AsyncStorage } from 'react-native'
logger.install({
storage: AsyncStorage,
})
`
`jsx
class LoggerComponent extends React.component {
componentDidCatch(e, info) {
this.props.logger.onError(e, {
...info,
type: 'react',
})
}
render() {
return this.props.children
}
}
`
`jsx`
`js`
const createLoggerMiddleware = (logger) => (store) => (next) => (action) => {
try {
return next(action)
} catch (e) {
logger.onError(e, {
action,
type: 'redux',
})
}
}
`js``
const store = createStore(
combineReducers(reducers),
applyMiddleware(createLoggerMiddleware(logger))
)