@blank-software/sentry-nestjs
v1.0.3
Published
Pacchetto npm per integrare NestJS con Sentry e Pino per massima observability
Readme
🚀 NestJS Sentry Integration
Integrazione completa e moderna di NestJS con @sentry/nestjs per error tracking, performance monitoring e logging nativo automatico.
✨ Caratteristiche
- 🔧 Setup zero-configuration - Funziona subito out-of-the-box
- 📊 Integrazione Sentry nativa - Usa @sentry/nestjs >= 9.41.0
- 📝 Dual Logging System - NestJS Logger + Sentry.logger in automatico
- 🎯 Interceptor automatico - Performance tracking e error handling
- 🏷️ Decorators avanzati - Accesso a User, Span e Scope
- 🌍 Modulo globale - Disponibile in tutta l'applicazione
- 🎭 TypeScript ready - Tipizzazione completa inclusa
📦 Installazione
npm install @blank-software/sentry-nestjs @sentry/nestjsNota: Non serve più installare pino o pino-sentry-transport! 🎉
🚀 Setup Rapido
1. Configurazione del modulo principale
import { Module } from '@nestjs/common';
import { SentryModule } from '@blank-software/sentry-nestjs';
@Module({
imports: [
SentryModule.forRoot({
dsn: process.env.SENTRY_DSN,
environment: process.env.NODE_ENV || 'development',
debug: process.env.NODE_ENV === 'development',
tracesSampleRate: 1.0,
enableLogging: true, // ✅ Abilita logging automatico
logLevels: ['log', 'warn', 'error'], // ✅ Tipi di log da inviare a Sentry
}),
// ... altri moduli
],
})
export class AppModule {}2. Main.ts (Interceptor globale opzionale)
import { NestFactory } from '@nestjs/core';
import { SentryInterceptor, SentryService } from '@blank-software/sentry-nestjs';
import { AppModule } from './app.module';
async function bootstrap() {
// ✅ Sentry è già inizializzato nel modulo!
const app = await NestFactory.create(AppModule);
// Interceptor globale per performance tracking automatico
app.useGlobalInterceptors(new SentryInterceptor(app.get(SentryService)));
await app.listen(3000);
}
bootstrap();📖 Utilizzo
🎯 Dual Logging System - Due Modi Per Loggare!
1. NestJS Logger (Automatico a Sentry)
import { Injectable, Logger } from '@nestjs/common';
@Injectable()
export class YourService {
private readonly logger = new Logger(YourService.name);
someMethod() {
// ✅ Tutti questi vanno automaticamente a Sentry
this.logger.log('Info message'); // 📝 Console + Sentry
this.logger.warn('Warning message'); // ⚠️ Console + Sentry
this.logger.error('Error message'); // ❌ Console + Sentry
this.logger.debug('Debug message'); // 🐛 Console + Sentry
}
}2. Sentry Logger Diretto (Con Metadati)
import { Injectable } from '@nestjs/common';
import { SentryService } from '@blank-software/sentry-nestjs';
import * as Sentry from '@sentry/nestjs';
@Injectable()
export class YourService {
constructor(private readonly sentryService: SentryService) {}
advancedLogging() {
// ✅ Usa Sentry.logger direttamente per log strutturati
Sentry.logger.info('User action performed', {
action: 'login',
userId: '123',
timestamp: new Date(),
metadata: { ip: '192.168.1.1', userAgent: 'Chrome' }
});
// ✅ Oppure usa i wrapper del service
this.sentryService.logInfo('Business logic executed', {
operation: 'data-processing',
duration: '150ms',
result: 'success'
});
this.sentryService.logError('Operation failed', {
error: 'validation-failed',
input: { field: 'email' },
severity: 'medium'
});
}
}🔄 Servizio Sentry Completo
import { Injectable } from '@nestjs/common';
import { SentryService } from '@blank-software/sentry-nestjs';
@Injectable()
export class YourService {
constructor(private readonly sentryService: SentryService) {}
async businessLogic() {
try {
// Imposta contesto utente
this.sentryService.setUser({
id: '123',
email: '[email protected]',
username: 'john_doe',
});
// Log strutturato per business logic
this.sentryService.logInfo('Business operation started', {
operation: 'user-workflow',
phase: 'initialization',
timestamp: new Date()
});
// Performance tracking
const transaction = this.sentryService.startTransaction({
name: 'business-operation',
op: 'task',
tags: { component: 'user-service', version: '1.0.0' }
});
// Simula operazione
await this.processUserData();
// Log successo
this.sentryService.logInfo('Business operation completed', {
operation: 'user-workflow',
phase: 'completion',
duration: '250ms',
result: 'success'
});
transaction.setStatus('ok');
transaction.finish();
} catch (error) {
// Log errore con contesto
this.sentryService.logError('Business operation failed', {
operation: 'user-workflow',
error: error.message,
phase: 'execution',
severity: 'high'
});
this.sentryService.captureException(error, 'YourService.businessLogic');
throw error;
}
}
private async processUserData() {
this.sentryService.withScope((scope) => {
scope.setTag('operation', 'data-processing');
scope.setContext('processing-info', {
timestamp: new Date(),
phase: 'validation'
});
// Log nel contesto dello scope
this.sentryService.logInfo('Processing user data', {
step: 'validation',
rules: ['email', 'phone', 'address']
});
});
}
}🏷️ Decorators Avanzati
import { Controller, Get, Post, Body } from '@nestjs/common';
import {
SentryUser,
SentryTransaction,
SentryScope,
User
} from '@blank-software/sentry-nestjs';
@Controller('users')
export class UsersController {
@Get('profile')
getProfile(
@SentryUser() user: User | null,
@SentryTransaction() transaction: any,
@SentryScope() scope: any,
) {
// Usa il scope per aggiungere contesto
scope.setTag('endpoint', 'user-profile');
scope.setContext('request-info', {
hasUser: !!user,
timestamp: new Date()
});
return {
user: user?.email || 'anonymous',
transactionName: transaction?.name || 'unknown'
};
}
@Post('update')
updateProfile(
@Body() data: any,
@SentryScope() scope: any
) {
// Aggiungi contesto specifico per questa richiesta
scope.setContext('update-data', data);
scope.setTag('operation', 'profile-update');
return { message: 'Profile updated', data };
}
}🔧 Controller di Debug Completo
import { Controller, Get, Post, Body, Logger } from '@nestjs/common';
import { SentryService } from '@blank-software/sentry-nestjs';
import * as Sentry from '@sentry/nestjs';
@Controller('debug')
export class DebugController {
private readonly logger = new Logger(DebugController.name);
constructor(private readonly sentryService: SentryService) {}
@Get('test-nestjs-logs')
testNestJSLogs() {
// ✅ NestJS Logger - Va automaticamente a Sentry
this.logger.log('✅ NestJS Info log - auto sent to Sentry');
this.logger.warn('⚠️ NestJS Warning log - auto sent to Sentry');
this.logger.error('❌ NestJS Error log - auto sent to Sentry');
this.logger.debug('🐛 NestJS Debug log - auto sent to Sentry');
return {
message: 'NestJS native logs sent automatically to Sentry!',
method: 'NestJS Logger',
timestamp: new Date()
};
}
@Get('test-sentry-logs')
testSentryLogs() {
// ✅ Sentry.logger diretto con metadati
Sentry.logger.info('📝 Direct Sentry info log', {
action: 'test_sentry_log',
component: 'debug-controller',
metadata: { test: true, version: '2.0.0' }
});
Sentry.logger.warn('⚠️ Direct Sentry warning log', {
action: 'test_sentry_warn',
level: 'warning',
details: { reason: 'test-scenario' }
});
Sentry.logger.error('❌ Direct Sentry error log', {
action: 'test_sentry_error',
severity: 'high',
context: { endpoint: '/debug/test-sentry-logs' }
});
// ✅ Service wrapper con metadati
this.sentryService.logInfo('📋 Service wrapper info log', {
method: 'testSentryLogs',
wrapper: 'SentryService',
timestamp: new Date()
});
return {
message: 'Direct Sentry logs with metadata sent!',
methods: ['Sentry.logger', 'SentryService wrappers'],
timestamp: new Date()
};
}
@Get('test-mixed-logs')
testMixedLogs() {
// ✅ Combina entrambi gli approcci
this.logger.log('🚀 NestJS: Starting mixed log test');
this.sentryService.logInfo('🎯 Sentry: Mixed log test started', {
test: 'mixed-logging',
phase: 'start',
approaches: ['nestjs', 'sentry-direct']
});
// Warning da entrambi
this.logger.warn('⚠️ NestJS: This is a warning');
Sentry.logger.warn('⚠️ Sentry: This is also a warning', {
source: 'direct',
correlation: 'mixed-test'
});
// Error da entrambi
this.logger.error('❌ NestJS: This is an error');
this.sentryService.logError('❌ Sentry: This is also an error', {
source: 'service-wrapper',
severity: 'medium',
correlation: 'mixed-test'
});
return {
message: 'Mixed logging test completed!',
approaches: ['NestJS Logger', 'Sentry.logger', 'SentryService'],
benefits: 'NestJS for simple logs, Sentry for structured data',
timestamp: new Date()
};
}
@Get('test-structured-logs')
testStructuredLogs() {
// ✅ Log strutturati per business analytics
this.sentryService.logInfo('User workflow started', {
workflow: 'user-onboarding',
step: 1,
stepName: 'registration',
userId: 'debug-user-123',
metadata: {
source: 'web-app',
campaign: 'debug-test',
timestamp: new Date(),
features: ['logging', 'analytics', 'monitoring']
}
});
this.sentryService.logInfo('User workflow progress', {
workflow: 'user-onboarding',
step: 2,
stepName: 'verification',
userId: 'debug-user-123',
progress: '50%',
metadata: {
verificationMethod: 'email',
attemptsRemaining: 2
}
});
this.sentryService.logInfo('User workflow completed', {
workflow: 'user-onboarding',
step: 3,
stepName: 'completion',
userId: 'debug-user-123',
progress: '100%',
duration: '125ms',
result: 'success'
});
return {
message: 'Structured logs sent for business analytics!',
workflow: 'user-onboarding',
steps: 3,
analyticsReady: true,
timestamp: new Date()
};
}
@Get('health')
health() {
return {
status: 'healthy',
service: 'sentry-nestjs-integration',
version: '2.0.0',
sentry: {
initialized: true,
logging: {
enabled: true,
methods: ['nestjs-auto', 'sentry-direct', 'service-wrappers'],
levels: ['log', 'warn', 'error', 'debug']
},
integrations: ['console', 'http', 'performance']
},
features: {
'dual-logging-system': true,
'nestjs-auto-logging': true,
'sentry-direct-logging': true,
'structured-logging': true,
'performance-tracking': true,
'error-tracking': true,
'context-management': true
},
endpoints: {
'GET /debug/test-nestjs-logs': 'Test NestJS native logging (auto to Sentry)',
'GET /debug/test-sentry-logs': 'Test direct Sentry logging with metadata',
'GET /debug/test-mixed-logs': 'Test mixed logging approaches',
'GET /debug/test-structured-logs': 'Test structured business logs',
'GET /debug/health': 'Health check with full feature overview'
},
recommendations: {
simple: 'Use NestJS Logger for simple application logs',
structured: 'Use Sentry.logger for business analytics with metadata',
mixed: 'Combine both approaches based on use case'
},
timestamp: new Date()
};
}
}⚙️ Configurazione Avanzata
SentryModule.forRoot({
dsn: process.env.SENTRY_DSN,
environment: process.env.NODE_ENV || 'production',
debug: process.env.NODE_ENV === 'development',
// Performance Monitoring
tracesSampleRate: 0.1, // 10% delle transazioni
profilesSampleRate: 0.1, // 10% profiling (se supportato)
// ✅ Logging Configuration
enableLogging: true, // Default: true - Abilita logging automatico
logLevels: ['log', 'warn', 'error', 'debug'], // Livelli da inviare a Sentry
// Custom integrations
integrations: [
// ✅ Console integration viene aggiunta automaticamente
// Puoi aggiungere altre integrazioni personalizzate qui
],
})🌐 Variabili d'ambiente
# Required
SENTRY_DSN=https://your-sentry-dsn-here
# Optional
NODE_ENV=production
SENTRY_DEBUG=false
SENTRY_TRACES_SAMPLE_RATE=0.1📋 Requisiti
- Node.js: >= 18.0.0
- NestJS: >= 10.0.0
- TypeScript: >= 5.0.0
- @sentry/nestjs: >= 9.41.0
🚀 Test degli Endpoint
# Test NestJS native logging (auto sent to Sentry)
curl http://localhost:3000/debug/test-nestjs-logs
# Test direct Sentry logging with metadata
curl http://localhost:3000/debug/test-sentry-logs
# Test mixed logging approaches
curl http://localhost:3000/debug/test-mixed-logs
# Test structured business logs
curl http://localhost:3000/debug/test-structured-logs
# Full health check
curl http://localhost:3000/debug/healthControlla la tua dashboard Sentry per vedere:
- 📝 Logs automatici da NestJS Logger
- 📊 Logs strutturati da Sentry.logger
- 🎯 Performance data dalle transazioni
- ❌ Errori con contesto completo
🔄 API Reference
SentryService - Metodi Principali
| Metodo | Descrizione | Esempio |
|--------|-------------|---------|
| logInfo(message, extra?) | Log info strutturato | service.logInfo('User login', { userId: '123' }) |
| logWarn(message, extra?) | Log warning strutturato | service.logWarn('Slow query', { duration: '500ms' }) |
| logError(message, extra?) | Log error strutturato | service.logError('API failure', { endpoint: '/api/users' }) |
| logDebug(message, extra?) | Log debug strutturato | service.logDebug('Debug info', { state: 'processing' }) |
| captureException(error, context?) | Cattura errore | service.captureException(error, 'MyService.method') |
| captureMessage(message, level?) | Invia messaggio | service.captureMessage('Info message', 'info') |
| setUser(user) | Imposta contesto utente | service.setUser({ id: '123', email: '[email protected]' }) |
| setTag(key, value) | Aggiunge tag | service.setTag('version', '1.0.0') |
| setContext(key, context) | Aggiunge contesto | service.setContext('request', { method: 'POST' }) |
| withScope(callback) | Scope temporaneo | service.withScope(scope => scope.setTag('temp', 'value')) |
Approcci di Logging
| Approccio | Quando Usare | Vantaggi | Esempio |
|-----------|--------------|----------|---------|
| NestJS Logger | Log applicativi semplici | Auto a Sentry, facile | logger.error('DB connection failed') |
| Sentry.logger | Business analytics | Metadati strutturati | Sentry.logger.info('User signup', { plan: 'pro' }) |
| Service Wrappers | Via di mezzo | Convenienza + metadati | service.logInfo('Order processed', { orderId: '123' }) |
Decorators
| Decorator | Descrizione | Uso |
|-----------|-------------|-----|
| @SentryUser() | Ottiene user corrente | method(@SentryUser() user: User) |
| @SentryScope() | Ottiene scope helper | method(@SentryScope() scope: any) |
| @SentryTransaction() | Ottiene transaction/span | method(@SentryTransaction() tx: any) |
📝 Licenza
MIT
🆙 Migrazione da v1.x
Se stai aggiornando dalla versione precedente:
1. Disinstalla dipendenze vecchie
npm uninstall @sentry/node pino pino-sentry-transport2. Installa nuove dipendenze
npm install @sentry/nestjs@^9.41.03. Aggiorna la configurazione
Prima (v1.x):
// ❌ Vecchia configurazione con Pino
SentryModule.forRoot({
dsn: process.env.SENTRY_DSN,
pinoOptions: { level: 'info' },
sentryPinoOptions: { level: 'error' }
});Dopo (v2.x):
// ✅ Nuova configurazione con dual logging
SentryModule.forRoot({
dsn: process.env.SENTRY_DSN,
environment: process.env.NODE_ENV,
enableLogging: true, // NestJS + Sentry logging automatico!
logLevels: ['log', 'warn', 'error', 'debug'] // Personalizzabile
});4. Aggiorna il codice
Prima:
// ❌ Vecchio approccio con Pino Logger
constructor(private pinoLogger: SentryPinoLogger) {}
this.pinoLogger.error('Error message');Dopo:
// ✅ Nuovo approccio dual logging
constructor(private sentryService: SentryService) {}
// Opzione 1: NestJS Logger (automatico a Sentry)
this.logger.error('Error message');
// Opzione 2: Sentry diretto con metadati
this.sentryService.logError('Error message', {
context: 'user-service',
severity: 'high'
});💡 Best Practices
📝 Quando Usare Ogni Approccio
NestJS Logger - Per log applicativi standard:
this.logger.log('Server started on port 3000');
this.logger.warn('Database connection slow');
this.logger.error('Authentication failed');Sentry.logger - Per business analytics e metriche:
Sentry.logger.info('User converted', {
userId: '123',
plan: 'premium',
conversionTime: '5min',
source: 'landing-page'
});Service Wrappers - Per comodità con metadati:
this.sentryService.logInfo('Order processed', {
orderId: 'ORD-123',
amount: 99.99,
paymentMethod: 'stripe'
});🏗️ Struttura Log Consigliata
// ✅ Log strutturato per analytics
{
message: 'User action completed',
action: 'purchase',
userId: '123',
metadata: {
product: 'premium-plan',
amount: 29.99,
currency: 'EUR',
paymentMethod: 'stripe',
timestamp: new Date(),
sessionId: 'sess-456'
}
}🐛 Bug Reports & Feature Requests
Se trovi un bug o vuoi richiedere una nuova funzionalità:
- Issues: Bitbucket Issues
- Discussions: Usa le discussions per domande generali
- Contributi: Pull requests are welcome!
🤝 Contributing
- Fork il repository
- Crea un branch per la feature (
git checkout -b feature/amazing-feature) - Commit le modifiche (
git commit -m 'Add amazing feature') - Push al branch (
git push origin feature/amazing-feature) - Apri una Pull Request
Made with ❤️ by Blank Software
🎯 Dual Logging System: La potenza di NestJS Logger per semplicità + Sentry.logger per analytics avanzate, tutto in automatico!
