## ![SumoLogic](https://www.sumologic.com/wp-content/themes/sumologic/assets/img/logo.png) for Web UI Developers
### Strategies and challenges, and groking the result
Created by [Xander Dumaine](https://www.xdumaine.com) / [@xanderdumaine](https://twitter.com/xanderdumaine)
released under [cc by-nc 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/)
## Disclaimer
The strategy presented here for logging is one we've seen success with. It is opinionated
but not prescriptive. There may be better solutions. Please share them with us if you find them.
## Why Log?
- "Can you open your console and see if there any errors?" does not scale
- Catch errors in the wild, with different browsers/versions
- Catch regressions in services causing UI problems
- Track problems accross app versions
- Gradually increase robustness
- A metric of where you need more unit testing
## Why Not Log?
- Client logs → increased https traffic
- Cached/buffered logs → increased client memory
- You're not *using* the logs
## What to Log
- Errors: Handled/unhandled/ajax
- Warnings: Potential problems
- Critical trace level logs
- WebRTC or WebSocket connections established
## What Not to Log
- Logs ≠ analytics
- Repetitive actions
- button clicks/navigations
- client/browser metadata
- ePHI
- Useless/Debug level logs
- UI load/bootstrap events
- Deprecations
## Logging API
### (PureCloud Public API)
`platform/api/v1/diagnostics/trace`
```javascript
{
"app": { "appId": "your-app-id" },
"traces": [
{
"level": "warn",
"message": "your-message-or-json-string",
"time": "time-error-occurred",
"topic": "your-application-context"
}
]
}
```
## Logging API
### (PureCloud Public API)
`platform/api/v1/diagnostics/trace`
```javascript
{
"app": { "appId": "collaborate-ui" },
"traces": [
{
"level": "warn",
"message": "{\"log\":[{\"name\":\"SyntaxError\",\"message\":\"Unexpected token o in JSON at position 1\"}]}",
"time": "2016-08-02T14:55:35.455Z",
"topic": "client.collaborate-ui.component:linkedin-import"
}
]
}
```
## Metadata to Consider
- Client JID
- User email
- Related Conversation Id
## Automatic Metadata
- User Agent
- Org guid
- User guid
## Limits
- 1 request per second
- 15kB per request
Multiple logs can be included in a single request, but watch
out for the 15kB limit
## Web Client Strategies
- Global application logger
- Automatic log context
- Stash logger - stashing and purging
- Levels, [black|white]listing
## Application Logger
- Handles uncaught exceptions
```javascript
window.onerror
```
- Attaches metadata and context
- Proxies to stash logger
## Application Logger
### Example
```javascript
stashLogger = globalStashLoggerForYourApplication;
window.onerror = function () {
stashLogger.error(...arguments);
return true; // stash logger will handle and log it
};
```
## Application Logger
### Example
`app/services/worker.js`
```javascript
// LoggerMixin is a utility that looks up the stash logging
// instance, and attaches context metadata (topic)
import LoggerMixin from '../utils/mixins/logger-mixin';
export default Ember.Service.extend(LoggerMixin, {
doSomeWork() {
this.doAjaxWork()
.then(this.handleWork)
.catch((err) => {
this.logger.error('Failed to handle work', err);
this.setError();
});
}
});
// log will automatically have topic: client.my-application.service:worker
```
## Limiting traces logged
- Stash logger limits levels generically
- Increase log level by topic (whitelist)
- Decrease/remove log level by topic (blacklist)
## Exponential backoff
### good, generic strategy
Send your log traces, then:
- on 413, cut traces in half
- 1/2ⁿ traces sent per request
- on 429, cut frequency in half
- 1/2ⁿ requests per second
- 2ⁿ seconds between request
## Limit backoff
### better, a priori strategy
- Limit your traces to ⩽ the API size limit per request
- Make requests at ⩽ the API rate limit per request
## Exponential limit backoff
### best of both worlds strategy
- Limit your traces to ⩽ the API size limit per request
- Make requests at ⩽ the API rate limit per request
- Exponentially backoff both for failure tolerance
## Purging
### Goal: Inbox 0
- Logs build client memory usage
- Delay in sending means potential for loss
- Get logs to the server ASAP
- Purge logs from memory ASAP
- Purge logs on on generic errors from logging service (`400`, `500`)
## Review
- Use global application logger util
- Limit information logged
- Attach useful metadata
- Backoff requests
## Finding your Logs
https://help.sumologic.com/Search
## Environments
- One account
- DCA/TCA/SCA, Special access for Prod
```
where env = "dev|test|stage|prod"
```
## Quick filter Fields
```
env = "prod" level = "error"
user = "user-guid" logger = "your-log-topic"
organization = "org-guid" app = "your-app-id"
source_category = "service-env"
```
## Time ranges
- Narrow down to find specific events
- Broaden to find trends or spikes
## Aggregates
```
| json field=name "jsonProp" as newField
| count by field
| sort by _count
| avg(field), min(field), max(field)
```
## You Try It
- Find all logs
- In the past 3 hours
- Associated with your SCA user
- from the donut service
## You Try It
```
user = "cc052c93-fc68-4dee-83ee-36863dc264af" and
_sourcecategory = "donut-stage"
```
## You Try It
- Find The Most frequent log messages
- In the past 3 hours
- Associated with your SCA user
- from the donut service
## You Try It
```
user = "cc052c93-fc68-4dee-83ee-36863dc264af" and
_sourcecategory = "donut-stage"
| json "message" as msg
| count by msg
| sort by _count
```
## You Try It
- Find all logs
- In the past 3 days
- In the "collaborate-ui" app
- in SCA
- Errors
- Matching "Cannot read property (.*) of undefined"
## You Try It
```
app = "collaborate-ui" and
(level = "ERROR" or level = "WARN")
| parse regex "Cannot read property (?<prop>.*?) of undefined"
| where env matches "stage"
```
or
```
app = "collaborate-ui" and
(level = "ERROR" or level = "WARN") and
_sourcecategory = "public_api_clients-stage" and
"Cannot read property" and "of undefined"
```
## Groking your logs
- Parse JSON
- Counts
- Aggregates
- time slices
- dashboards
### Example
Most frequent errors or warnings
```
app = "collaborate-ui" and
(level = "ERROR" or level = "WARN")
| json field=_raw "message"
| json field=message "log[0].message" as errMsg
| where env matches "stage"
| count by errmsg
| sort by _count
```
### Example
Average packet loss over time (every minute)
```
_sourcecategory="public_api_clients-stage" and "collaborate-ui"
| json "message"
| json field=message
"log[0].webrtcStats.tracks[1].loss",
"log[0].webrtcStats.tracks[1].kind"
as packetLoss, kind
| where (kind = "video")
| timeslice 1m
| avg(packetLoss) by _timeslice
```
## Alerting and Reporting
- Create a query
- Schedule the query
- Send emails, alerts, webhooks, etc
- WebHooks must be configured by an Admin
Thank You.
this.logger.info('Any questions?');