|
| 1 | +# UI Logging - Metrics Tracking Utility |
| 2 | + |
| 3 | +## AI Agent Routing (Do Not Start Here) |
| 4 | + |
| 5 | +If you are an AI assistant or tool reading this file **as your first entry point**, do **not** start your reasoning or code generation workflow from here. |
| 6 | + |
| 7 | +- **Primary entrypoint:** Always begin with the **nearest parent** contact-center AI docs `AGENTS.md` (for example, the root `ai-docs/AGENTS.md` at the repository root). |
| 8 | +- **Process:** |
| 9 | + - Load and follow the instructions and templates in that parent `AGENTS.md`. |
| 10 | + - Only after a parent `AGENTS.md` explicitly routes you to this file should you treat this document as package-specific guidance. |
| 11 | +- **Never** skip the parent `AGENTS.md` even if the user prompt directly mentions this specific package or file. |
| 12 | + |
| 13 | +Once you have gone through the parent `AGENTS.md` and been routed here, you can use the rest of this file as the authoritative reference for the `@webex/cc-ui-logging` package. |
| 14 | + |
| 15 | +## Overview |
| 16 | + |
| 17 | +UI Logging is a lightweight utility package that provides logging and metrics tracking capabilities for contact center widgets. It includes a Higher-Order Component (HOC) called `withMetrics` that automatically tracks widget lifecycle events, and a `logMetrics` function for custom event logging. |
| 18 | + |
| 19 | +**Package:** `@webex/cc-ui-logging` |
| 20 | + |
| 21 | +**Version:** See [package.json](../package.json) |
| 22 | + |
| 23 | +--- |
| 24 | + |
| 25 | +## Why and What is This Package Used For? |
| 26 | + |
| 27 | +### Purpose |
| 28 | + |
| 29 | +The UI Logging package enables observability and monitoring for contact center widgets. It: |
| 30 | + |
| 31 | +- **Tracks widget lifecycle** - Automatically logs mount, unmount, and updates |
| 32 | +- **Provides HOC wrapper** - Easy integration with minimal code changes |
| 33 | +- **Logs to store logger** - Integrates with existing logging infrastructure |
| 34 | +- **Supports custom metrics** - Log custom events with additional context |
| 35 | +- **[WIP]Optimizes re-renders** - Includes shallow props comparison for performance |
| 36 | + |
| 37 | +### Key Capabilities |
| 38 | + |
| 39 | +- **withMetrics HOC**: Wraps components to auto-track lifecycle events |
| 40 | +- **logMetrics Function**: Manually log custom events |
| 41 | +- **havePropsChanged Utility**: Shallow comparison to prevent unnecessary re-renders |
| 42 | +- **Type-Safe**: Full TypeScript support with WidgetMetrics type |
| 43 | +- **Store Integration**: Uses store.logger for centralized logging |
| 44 | + |
| 45 | +--- |
| 46 | + |
| 47 | +## Examples and Use Cases |
| 48 | + |
| 49 | +### Getting Started |
| 50 | + |
| 51 | +#### Basic HOC Usage |
| 52 | + |
| 53 | +```typescript |
| 54 | +import { withMetrics } from '@webex/cc-ui-logging'; |
| 55 | +import MyWidget from './MyWidget'; |
| 56 | + |
| 57 | +// Wrap your widget with metrics tracking |
| 58 | +const MyWidgetWithMetrics = withMetrics(MyWidget, 'MyWidget'); |
| 59 | + |
| 60 | +// Use the wrapped component |
| 61 | +function App() { |
| 62 | + return <MyWidgetWithMetrics prop1="value" />; |
| 63 | +} |
| 64 | + |
| 65 | +// Automatically logs: |
| 66 | +// - WIDGET_MOUNTED when component mounts |
| 67 | +// - WIDGET_UNMOUNTED when component unmounts |
| 68 | +``` |
| 69 | + |
| 70 | +### Common Use Cases |
| 71 | + |
| 72 | +#### 1. Tracking Widget Lifecycle |
| 73 | + |
| 74 | +```typescript |
| 75 | +import { withMetrics } from '@webex/cc-ui-logging'; |
| 76 | +import { StationLogin } from '@webex/cc-widget'; |
| 77 | + |
| 78 | +// Automatically tracks mount/unmount |
| 79 | +const StationLoginWithMetrics = withMetrics( |
| 80 | + StationLogin, |
| 81 | + 'StationLogin' |
| 82 | +); |
| 83 | + |
| 84 | +// When used in app: |
| 85 | +<StationLoginWithMetrics /> |
| 86 | + |
| 87 | +// Logs on mount: |
| 88 | +// { |
| 89 | +// widgetName: 'StationLogin', |
| 90 | +// event: 'WIDGET_MOUNTED', |
| 91 | +// timestamp: 1700000000000 |
| 92 | +// } |
| 93 | + |
| 94 | +// Logs on unmount: |
| 95 | +// { |
| 96 | +// widgetName: 'StationLogin', |
| 97 | +// event: 'WIDGET_UNMOUNTED', |
| 98 | +// timestamp: 1700000100000 |
| 99 | +// } |
| 100 | +``` |
| 101 | + |
| 102 | +### Integration Patterns |
| 103 | + |
| 104 | +#### With Widget Components |
| 105 | + |
| 106 | +```typescript |
| 107 | +import { withMetrics } from '@webex/cc-ui-logging'; |
| 108 | +import { observer } from 'mobx-react-lite'; |
| 109 | +import { UserStateComponent } from '@webex/cc-components'; |
| 110 | +import store from '@webex/cc-store'; |
| 111 | + |
| 112 | +// 1. Create internal component |
| 113 | +const UserStateInternal = observer(({ onStateChange }) => { |
| 114 | + const props = { |
| 115 | + idleCodes: store.idleCodes, |
| 116 | + currentState: store.currentState, |
| 117 | + setAgentStatus: (code) => store.setCurrentState(code), |
| 118 | + onStateChange, |
| 119 | + }; |
| 120 | + |
| 121 | + return <UserStateComponent {...props} />; |
| 122 | +}); |
| 123 | + |
| 124 | +// 2. Wrap with metrics HOC |
| 125 | +const UserState = withMetrics(UserStateInternal, 'UserState'); |
| 126 | + |
| 127 | +export { UserState }; |
| 128 | +``` |
| 129 | + |
| 130 | +#### With Error Boundaries |
| 131 | + |
| 132 | +````typescript |
| 133 | +import { withMetrics } from '@webex/cc-ui-logging'; |
| 134 | +import { ErrorBoundary } from 'react-error-boundary'; |
| 135 | + |
| 136 | +const UserStateInternal = observer(({ onStateChange }) => { |
| 137 | + const props = { |
| 138 | + idleCodes: store.idleCodes, |
| 139 | + currentState: store.currentState, |
| 140 | + setAgentStatus: (code) => store.setCurrentState(code), |
| 141 | + onStateChange, |
| 142 | + }; |
| 143 | + |
| 144 | + return <UserStateComponent {...props} />; |
| 145 | +}); |
| 146 | + |
| 147 | +function Widget(props) { |
| 148 | + const handleError = (error: Error) => { |
| 149 | + // Log error via metrics |
| 150 | + }; |
| 151 | + |
| 152 | + return ( |
| 153 | + <ErrorBoundary onError={handleError}> |
| 154 | + <UserStateInternal {...props} /> |
| 155 | + </ErrorBoundary> |
| 156 | + ); |
| 157 | +} |
| 158 | +--- |
| 159 | + |
| 160 | +## Dependencies |
| 161 | + |
| 162 | +**Note:** For exact versions, see [package.json](../package.json) |
| 163 | + |
| 164 | +### Runtime Dependencies |
| 165 | + |
| 166 | +| Package | Purpose | |
| 167 | +| ----------------- | ---------------------------------- | |
| 168 | +| `@webex/cc-store` | Access to store.logger for logging | |
| 169 | + |
| 170 | +### Peer Dependencies |
| 171 | + |
| 172 | +| Package | Purpose | |
| 173 | +| ----------- | ------------------------- | |
| 174 | +| `react` | React framework (for HOC) | |
| 175 | +| `react-dom` | React DOM (for HOC) | |
| 176 | + |
| 177 | +### Development Dependencies |
| 178 | + |
| 179 | +Key development tools (see [package.json](../package.json) for versions): |
| 180 | + |
| 181 | +- TypeScript |
| 182 | +- Jest (testing) |
| 183 | +- Webpack (bundling) |
| 184 | + |
| 185 | +--- |
| 186 | + |
| 187 | +## API Reference |
| 188 | + |
| 189 | +### withMetrics HOC |
| 190 | + |
| 191 | +```typescript |
| 192 | +function withMetrics<P extends object>( |
| 193 | + Component: React.ComponentType<P>, |
| 194 | + widgetName: string |
| 195 | +): React.MemoExoticComponent<React.FC<P>>; |
| 196 | +```` |
| 197 | +
|
| 198 | +**Parameters:** |
| 199 | +
|
| 200 | +- `Component` - React component to wrap |
| 201 | +- `widgetName` - Name for metric identification |
| 202 | +
|
| 203 | +**Returns:** Memoized component with automatic metrics tracking |
| 204 | +
|
| 205 | +**Behavior:** |
| 206 | +
|
| 207 | +- Wraps component with React.memo |
| 208 | +- Logs WIDGET_MOUNTED on mount |
| 209 | +- Logs WIDGET_UNMOUNTED on unmount |
| 210 | +
|
| 211 | +--- |
| 212 | +
|
| 213 | +### logMetrics Function |
| 214 | +
|
| 215 | +```typescript |
| 216 | +function logMetrics(metric: WidgetMetrics): void; |
| 217 | + |
| 218 | +type WidgetMetrics = { |
| 219 | + widgetName: string; |
| 220 | + event: 'WIDGET_MOUNTED' | 'ERROR' | 'WIDGET_UNMOUNTED' | 'PROPS_UPDATED'; |
| 221 | + props?: Record<string, any>; |
| 222 | + timestamp: number; |
| 223 | + additionalContext?: Record<string, any>; |
| 224 | +}; |
| 225 | +``` |
| 226 | + |
| 227 | +**Parameters:** |
| 228 | + |
| 229 | +- `metric.widgetName` - Widget identifier |
| 230 | +- `metric.event` - Event type |
| 231 | +- `metric.props` - Optional widget props snapshot |
| 232 | +- `metric.timestamp` - Unix timestamp |
| 233 | +- `metric.additionalContext` - Optional additional data |
| 234 | + |
| 235 | +**Behavior:** |
| 236 | + |
| 237 | +- Checks if `store.logger` exists |
| 238 | +- Logs warning if no logger available |
| 239 | +- Calls `store.logger.log()` with formatted JSON |
| 240 | + |
| 241 | +--- |
| 242 | + |
| 243 | +## Installation |
| 244 | + |
| 245 | +```bash |
| 246 | +# Install as dependency |
| 247 | +yarn add @webex/cc-widget |
| 248 | +
|
| 249 | +# Used internally by widgets, usually not directly installed |
| 250 | +``` |
| 251 | + |
| 252 | +--- |
| 253 | + |
| 254 | +## Additional Resources |
| 255 | + |
| 256 | +For detailed HOC implementation, metrics flow, and performance optimization, see [architecture.md](./architecture.md). |
| 257 | + |
| 258 | +--- |
| 259 | + |
| 260 | +_Last Updated: 2025-11-26_ |
0 commit comments