@azure/mcp-win32-x64
Version:
Azure MCP Server - Model Context Protocol implementation for Azure, for win32 on x64
261 lines (202 loc) • 6.5 kB
Markdown
# Basic Azure Monitor Setup for Node.js with Winston Logging
This guide shows how to add Azure Monitor OpenTelemetry to a Node.js application using Winston for logging.
## Prerequisites
- Node.js 14.x or higher
- npm or yarn
- Node.js application with Winston (`winston` package)
- Azure Application Insights resource
## Step 1: Install Package
```bash
npm install @azure/monitor-opentelemetry
```
## Step 2: Initialize at Startup
Create or update your main entry point (typically `index.js` or `server.js`):
```javascript
// IMPORTANT: This must be the first line, before any other imports
const { useAzureMonitor } = require('@azure/monitor-opentelemetry');
// Initialize Azure Monitor with Winston log collection enabled
useAzureMonitor({
azureMonitorExporterOptions: {
connectionString: process.env.APPLICATIONINSIGHTS_CONNECTION_STRING
},
instrumentationOptions: {
winston: { enabled: true }
}
});
// Now load your application code
const express = require('express');
const winston = require('winston');
// Create Winston logger
const logger = winston.createLogger({
level: process.env.LOG_LEVEL || 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.errors({ stack: true }),
winston.format.json()
),
defaultMeta: { service: 'my-app' },
transports: [
new winston.transports.Console({
format: winston.format.combine(
winston.format.colorize(),
winston.format.simple()
)
})
]
});
const app = express();
const port = process.env.PORT || 3000;
app.use(express.json());
// Request logging middleware
app.use((req, res, next) => {
logger.info('Incoming request', {
method: req.method,
path: req.path
});
next();
});
app.get('/api/users', (req, res) => {
logger.info('Fetching users');
res.json([{ id: 1, name: 'Alice' }]);
});
app.listen(port, () => {
logger.info(`Server listening on port ${port}`);
});
```
## Step 3: Configure Connection String
Create a `.env` file in your project root:
```env
APPLICATIONINSIGHTS_CONNECTION_STRING=InstrumentationKey=00000000-0000-0000-0000-000000000000;IngestionEndpoint=https://...
LOG_LEVEL=info
PORT=3000
```
Install `dotenv` to load environment variables:
```bash
npm install dotenv
```
Load it at the very top of your entry file:
```javascript
require('dotenv').config();
const { useAzureMonitor } = require('@azure/monitor-opentelemetry');
// ... rest of code
```
## What Gets Collected
With Winston instrumentation enabled, the following log data is sent to Azure Monitor:
- **Log level**: error, warn, info, debug, etc.
- **Log message**: The log content
- **Metadata**: Any additional properties passed to the logger
- **Timestamp**: When the log was created
- **Trace context**: Correlation with distributed traces
## Log Level Mapping
Winston log levels are mapped to Application Insights severity levels:
| Winston Level | Application Insights Severity |
|--------------|------------------------------|
| error | Error |
| warn | Warning |
| info | Information |
| http | Information |
| verbose | Verbose |
| debug | Verbose |
| silly | Verbose |
## Step 4: Structured Logging Best Practices
### Add Context to Logs
```javascript
// Good: Structured logging with context
logger.info('User created', {
userId: user.id,
email: user.email,
action: 'create'
});
// Good: Error logging with stack trace
logger.error('Failed to create user', {
error: err.message,
stack: err.stack,
email: req.body.email
});
```
### Correlation with Requests
Logs are automatically correlated with HTTP requests when using Express:
```javascript
app.get('/api/users/:id', (req, res) => {
// This log will be correlated with the request trace
logger.info('Fetching user', { userId: req.params.id });
try {
const user = getUserById(req.params.id);
logger.debug('User found', { user });
res.json(user);
} catch (error) {
logger.error('User not found', {
userId: req.params.id,
error: error.message
});
res.status(404).json({ error: 'User not found' });
}
});
```
## Step 5: Custom Telemetry (Optional)
Combine logging with custom spans:
```javascript
const { trace } = require('@opentelemetry/api');
app.post('/api/orders', async (req, res) => {
const tracer = trace.getTracer('my-app');
await tracer.startActiveSpan('create-order', async (span) => {
logger.info('Creating order', { items: req.body.items.length });
try {
const order = await createOrder(req.body);
logger.info('Order created successfully', {
orderId: order.id,
total: order.total
});
span.setAttribute('order.id', order.id);
res.status(201).json(order);
} catch (error) {
logger.error('Failed to create order', {
error: error.message,
stack: error.stack
});
span.recordException(error);
span.setStatus({ code: 2, message: error.message });
res.status(500).json({ error: 'Failed to create order' });
} finally {
span.end();
}
});
});
```
## Viewing Logs in Azure Portal
1. Open your Application Insights resource in Azure Portal
2. Navigate to "Logs" under Monitoring
3. Query traces table:
```kusto
traces
| where timestamp > ago(1h)
| where customDimensions.service == "my-app"
| project timestamp, message, severityLevel, customDimensions
| order by timestamp desc
```
4. Use "Transaction search" to see logs correlated with requests
## Troubleshooting
### Winston logs not appearing
1. Ensure `winston` instrumentation is enabled in options
2. Verify `useAzureMonitor()` is called **before** importing `winston`
3. Check that the connection string is valid
### Too many logs being sent
Control log volume by adjusting the log level:
```javascript
const logger = winston.createLogger({
level: process.env.NODE_ENV === 'production' ? 'warn' : 'debug',
// ...
});
```
Or use sampling:
```javascript
useAzureMonitor({
azureMonitorExporterOptions: {
connectionString: process.env.APPLICATIONINSIGHTS_CONNECTION_STRING
},
instrumentationOptions: {
winston: { enabled: true }
},
samplingRatio: 0.5 // Sample 50% of telemetry
});
```