Skip to Content
Nueva versión 12 disponible 🎉
LicensingInformesInformes personalizados

Informes personalizados

Además de los informes integrados de excepción y de uso de licencia, Babel Licensing permite crear informes personalizados adaptados a las necesidades concretas de su aplicación. Con los informes personalizados puede enviar cualquier dato estructurado a su Babel Licensing Service para recopilarlo, analizarlo y supervisarlo de forma centralizada.

Descripción general

Los informes personalizados son útiles para:

  • Eventos de seguridad: detecte y notifique posibles intentos de ataque, accesos no autorizados o comportamientos sospechosos
  • Métricas de la aplicación: haga el seguimiento de métricas personalizadas de rendimiento o de uso de la aplicación
  • Eventos de negocio: notifique eventos o hitos de negocio importantes
  • Diagnóstico: envíe datos de diagnóstico personalizados para la solución de problemas
  • Pistas de auditoría: cree registros de auditoría para los requisitos de cumplimiento

Ejemplo de aplicación de consola

Para empezar con un ejemplo práctico, clone el repositorio console-custom-report-example, que muestra cómo crear y enviar informes personalizados con la funcionalidad de Babel Reporting.

Abrir un cliente Git

Abra el cliente Git que prefiera o la línea de comandos.

Clonar el repositorio

Clone el repositorio de GitHub con el comando siguiente:

git clone https://github.com/babelfornet/console-custom-report-example.git

Una vez clonado el repositorio, vaya al directorio del proyecto:

cd console-custom-report-example

Examinar y ejecutar el ejemplo

Ya puede examinar y ejecutar el código de ejemplo.

El ejemplo console-custom-report-example muestra cómo integrar la biblioteca cliente de Babel Licensing en su aplicación para crear informes personalizados y enviarlos al Babel Licensing Service. A continuación se explica el código paso a paso:

  1. Inicialización de BabelReporting: el código de ejemplo inicializa un objeto BabelReporting y lo configura con la URL del servicio y el identificador del cliente.
private BabelReporting CreateReportingClient() { var reporting = new BabelReporting(); reporting.Configuration.ClientId = ClientId; reporting.Configuration.ServiceUrl = ServiceUrl; reporting.Configuration.UseHttp(http => { http.Timeout = TimeSpan.FromSeconds(3); http.Handler = new HttpClientHandler() { ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true }; }); reporting.BeforeSendReport += (s, e) => { e.Report.Properties.Add("cmdline", Environment.CommandLine); e.Report.Properties.Add("username", Environment.UserName); }; return reporting; }
  1. Clave de usuario: el código de ejemplo usa una clave de usuario (UserKey) que autoriza al cliente a enviar informes. Sustitúyala por una clave de usuario válida. Para generar una clave de usuario, consulte los apartados Licencia flotante o Activación de licencia.

  2. Clase de informe personalizado: la clase HackDetectionReport hereda de Report y define propiedades personalizadas para hacer el seguimiento de eventos de seguridad. Usa ReportPlot para crear gráficos interactivos que se muestran en la aplicación web:

class HackDetectionReport : Report { public string HackingType { get; set; } = "unknown"; public string AttackMethod { get; set; } = "unknown"; public string HackDetails { get; set; } = "no_details"; public HackDetectionReport() : base("HackDetection") { } public override void Build() { // Add custom hack detection information Properties.Add("machineName", Environment.MachineName); Properties.Add("hackingType", HackingType); Properties.Add("attackMethod", AttackMethod); Properties.Add("hackDetails", HackDetails); // Add attack distribution pie chart var attackDistribution = new ReportPlot(ReportPlotType.Pie, "Attack Type Distribution") .SetHeight(400) .AddSeries("Attacks", new List<object> { new { type = "SQL Injection", count = 45 }, new { type = "XSS", count = 32 }, new { type = "CSRF", count = 18 }, new { type = "Path Traversal", count = 12 }, new { type = "Brute Force", count = 8 } }); attackDistribution.Series[0].ArgumentField = "type"; attackDistribution.Series[0].ValueField = "count"; Properties.Add("attackDistribution", attackDistribution.ToDictionary()); // Add attack timeline line chart var attackTimeline = new ReportPlot(ReportPlotType.Line, "Attack Attempts Over Time") .SetAxisTitles("Time", "Attack Count") .SetHeight(350) .AddSeries("Today", new List<object> { new { hour = "00:00", attempts = 5 }, new { hour = "04:00", attempts = 3 }, new { hour = "08:00", attempts = 15 }, new { hour = "12:00", attempts = 28 }, new { hour = "16:00", attempts = 22 }, new { hour = "20:00", attempts = 18 } }) .AddSeries("Yesterday", new List<object> { new { hour = "00:00", attempts = 4 }, new { hour = "04:00", attempts = 2 }, new { hour = "08:00", attempts = 12 }, new { hour = "12:00", attempts = 20 }, new { hour = "16:00", attempts = 25 }, new { hour = "20:00", attempts = 15 } }); attackTimeline.Series[0].ArgumentField = "hour"; attackTimeline.Series[0].ValueField = "attempts"; attackTimeline.Series[1].ArgumentField = "hour"; attackTimeline.Series[1].ValueField = "attempts"; Properties.Add("attackTimeline", attackTimeline.ToDictionary()); // Add severity bar chart var severityChart = new ReportPlot(ReportPlotType.Bar, "Attack Severity Levels") .SetAxisTitles("Severity", "Incidents") .SetHeight(350) .AddSeries("Last 24h", new List<object> { new { severity = "Critical", incidents = 8 }, new { severity = "High", incidents = 25 }, new { severity = "Medium", incidents = 42 }, new { severity = "Low", incidents = 30 } }); severityChart.Series[0].ArgumentField = "severity"; severityChart.Series[0].ValueField = "incidents"; Properties.Add("severityChart", severityChart.ToDictionary()); // Add IP source area chart var ipSourceChart = new ReportPlot(ReportPlotType.Area, "Attack Sources by Region") .SetAxisTitles("Hour", "Unique IPs") .SetHeight(350) .AddSeries("Asia", new List<object> { new { hour = "00:00", ips = 12 }, new { hour = "06:00", ips = 18 }, new { hour = "12:00", ips = 25 }, new { hour = "18:00", ips = 22 } }) .AddSeries("Europe", new List<object> { new { hour = "00:00", ips = 8 }, new { hour = "06:00", ips = 15 }, new { hour = "12:00", ips = 20 }, new { hour = "18:00", ips = 18 } }) .AddSeries("Americas", new List<object> { new { hour = "00:00", ips = 5 }, new { hour = "06:00", ips = 10 }, new { hour = "12:00", ips = 15 }, new { hour = "18:00", ips = 12 } }); ipSourceChart.Series[0].ArgumentField = "hour"; ipSourceChart.Series[0].ValueField = "ips"; ipSourceChart.Series[1].ArgumentField = "hour"; ipSourceChart.Series[1].ValueField = "ips"; ipSourceChart.Series[2].ArgumentField = "hour"; ipSourceChart.Series[2].ValueField = "ips"; Properties.Add("ipSourceChart", ipSourceChart.ToDictionary()); base.Build(); } }
  1. Evento BeforeSendReport: el ejemplo se suscribe al evento BeforeSendReport, que permite añadir más propiedades a los informes antes de enviarlos. En este controlador de eventos se añaden propiedades personalizadas como cmdline (línea de comandos) y username (nombre del usuario actual).

  2. Envío del informe: el método SendAsync envía el informe personalizado al Babel Licensing Service:

private async Task SendHackDetectionReportAsync() { var hackReport = new HackDetectionReport { HackingType = "SQL Injection", AttackMethod = "Malicious Input", HackDetails = "Detected SQL keywords in user input" }; await _reporting.SendAsync(UserKey, hackReport); Console.WriteLine("HackDetectionReport sent."); }

Ejemplo de informe personalizado

El ejemplo console-custom-report-example es una demostración práctica de cómo crear tipos de informe personalizados y enviarlos al Babel Licensing Service. Al integrar informes personalizados en sus aplicaciones, puede hacer el seguimiento de eventos de seguridad, métricas de la aplicación, eventos de negocio y cualquier otro dato estructurado que sea relevante para su aplicación.

Crear un informe personalizado

Para crear un informe personalizado, herede de la clase base Report:

using Babel.Licensing.Reports; public class HackDetectionReport : Report { // Custom properties for your report public string HackingType { get; set; } = "unknown"; public string AttackMethod { get; set; } = "unknown"; public string HackDetails { get; set; } = "no_details"; // Constructor: specify report name public HackDetectionReport() : base("HackDetection") { } // Build method: populate report properties public override void Build() { // Add custom properties to the report Properties.Add("machine_name", Environment.MachineName); Properties.Add("hacking_type", HackingType); Properties.Add("attack_method", AttackMethod); Properties.Add("detection_details", HackDetails); Properties.Add("detected_at", DateTime.UtcNow); // Call base to generate final JSON structure base.Build(); } }

La clase base Report

La clase Report es la base de todos los informes:

Propiedades principales

  • Name: identificador único del tipo de informe (por ejemplo, «HackDetection», «PerformanceMetrics»)
  • Content: datos del informe serializados en JSON (generados por Build())
  • Version: versión del formato del informe (actualmente «1.0»)
  • Date: marca de tiempo de la creación del informe
  • Encrypted: indicador de si el contenido está cifrado
  • Properties: diccionario para datos personalizados de clave y valor

Métodos principales

  • Build(): invalide este método para rellenar sus propiedades personalizadas
  • Create(string report, string password): deserializa un informe a partir de JSON
  • FromException(Exception ex, ExceptionReportOptions options): método de fábrica para los informes de excepción

Enviar informes personalizados

Una vez creada la clase del informe personalizado, envíelo con BabelReporting:

using Babel.Licensing.Services; // Initialize reporting service var reporting = new BabelReporting(); reporting.Configuration.ServiceUrl = "https://licensing.example.com"; reporting.Configuration.ClientId = "MyApplication"; // Create and configure your custom report var hackReport = new HackDetectionReport { HackingType = "SQL Injection", AttackMethod = "Malicious Input", HackDetails = "Detected SQL keywords in user input: ' OR '1'='1" }; // Send the report var result = await reporting.SendAsync(userKey, hackReport); if (result.Success) { Console.WriteLine($"Report sent: {result.ReportUid}"); } else { Console.WriteLine($"Failed: {result.Error?.Message}"); }

Ejemplos reales

Ejemplo 1: informe de eventos de seguridad

Detecte y notifique posibles amenazas de seguridad:

public class SecurityEventReport : Report { public string EventType { get; set; } public string Severity { get; set; } public string SourceIP { get; set; } public string UserAgent { get; set; } public string RequestPath { get; set; } public Dictionary<string, string> AdditionalData { get; set; } public SecurityEventReport() : base("SecurityEvent") { AdditionalData = new Dictionary<string, string>(); } public override void Build() { Properties.Add("event_type", EventType); Properties.Add("severity", Severity); Properties.Add("source_ip", SourceIP); Properties.Add("user_agent", UserAgent); Properties.Add("request_path", RequestPath); Properties.Add("timestamp", DateTime.UtcNow); Properties.Add("machine_id", GetMachineId()); // Add all additional data foreach (var kvp in AdditionalData) { Properties.Add(kvp.Key, kvp.Value); } base.Build(); } private string GetMachineId() { // Implementation to get unique machine identifier return Environment.MachineName; } } // Usage public async Task ReportSuspiciousLogin(string ipAddress, string userAgent) { var report = new SecurityEventReport { EventType = "SuspiciousLogin", Severity = "High", SourceIP = ipAddress, UserAgent = userAgent, RequestPath = "/api/auth/login" }; report.AdditionalData.Add("failed_attempts", "5"); report.AdditionalData.Add("time_window", "60s"); await _reporting.SendAsync(_userKey, report); }

Ejemplo 2: informe de métricas de rendimiento

Haga el seguimiento de las métricas de rendimiento de la aplicación:

public class PerformanceMetricsReport : Report { public double AverageResponseTime { get; set; } public double PeakResponseTime { get; set; } public int TotalRequests { get; set; } public int FailedRequests { get; set; } public double CpuUsage { get; set; } public double MemoryUsage { get; set; } public TimeSpan Uptime { get; set; } public PerformanceMetricsReport() : base("PerformanceMetrics") { } public override void Build() { Properties.Add("average_response_time_ms", AverageResponseTime); Properties.Add("peak_response_time_ms", PeakResponseTime); Properties.Add("total_requests", TotalRequests); Properties.Add("failed_requests", FailedRequests); Properties.Add("error_rate", CalculateErrorRate()); Properties.Add("cpu_usage_percent", CpuUsage); Properties.Add("memory_usage_mb", MemoryUsage); Properties.Add("uptime_hours", Uptime.TotalHours); Properties.Add("collection_time", DateTime.UtcNow); base.Build(); } private double CalculateErrorRate() { if (TotalRequests == 0) return 0; return (double)FailedRequests / TotalRequests * 100; } } // Usage with periodic reporting public class MetricsCollector { private readonly BabelReporting _reporting; private readonly Timer _timer; private readonly PerformanceMonitor _monitor; public MetricsCollector(BabelReporting reporting, string userKey) { _reporting = reporting; _monitor = new PerformanceMonitor(); // Report metrics every hour _timer = new Timer(async _ => { var metrics = _monitor.GetCurrentMetrics(); var report = new PerformanceMetricsReport { AverageResponseTime = metrics.AvgResponseTime, PeakResponseTime = metrics.PeakResponseTime, TotalRequests = metrics.TotalRequests, FailedRequests = metrics.FailedRequests, CpuUsage = metrics.CpuUsage, MemoryUsage = metrics.MemoryUsage, Uptime = metrics.Uptime }; await _reporting.SendAsync(userKey, report); }, null, TimeSpan.FromHours(1), TimeSpan.FromHours(1)); } }

Ejemplo 3: informe de eventos de negocio

Haga el seguimiento de los eventos de negocio importantes:

public class BusinessEventReport : Report { public string EventCategory { get; set; } public string EventAction { get; set; } public string UserId { get; set; } public string EntityType { get; set; } public string EntityId { get; set; } public decimal? TransactionAmount { get; set; } public Dictionary<string, object> Metadata { get; set; } public BusinessEventReport() : base("BusinessEvent") { Metadata = new Dictionary<string, object>(); } public override void Build() { Properties.Add("event_category", EventCategory); Properties.Add("event_action", EventAction); Properties.Add("user_id", UserId); Properties.Add("entity_type", EntityType); Properties.Add("entity_id", EntityId); Properties.Add("timestamp", DateTime.UtcNow); if (TransactionAmount.HasValue) { Properties.Add("transaction_amount", TransactionAmount.Value); } // Add metadata foreach (var kvp in Metadata) { Properties.Add(kvp.Key, kvp.Value); } base.Build(); } } // Usage public async Task ReportPurchase(string userId, string orderId, decimal amount) { var report = new BusinessEventReport { EventCategory = "Sales", EventAction = "Purchase", UserId = userId, EntityType = "Order", EntityId = orderId, TransactionAmount = amount }; report.Metadata.Add("payment_method", "CreditCard"); report.Metadata.Add("currency", "USD"); await _reporting.SendAsync(_userKey, report); }

Ejemplo 4: informe de diagnóstico

Envíe información de diagnóstico detallada:

public class DiagnosticReport : Report { public string Component { get; set; } public string Status { get; set; } public string ErrorMessage { get; set; } public Dictionary<string, string> ConfigurationSettings { get; set; } public Dictionary<string, string> HealthChecks { get; set; } public DiagnosticReport() : base("Diagnostic") { ConfigurationSettings = new Dictionary<string, string>(); HealthChecks = new Dictionary<string, string>(); } public override void Build() { Properties.Add("component", Component); Properties.Add("status", Status); Properties.Add("error_message", ErrorMessage ?? "None"); Properties.Add("timestamp", DateTime.UtcNow); Properties.Add("application_version", GetApplicationVersion()); // Add configuration settings var configJson = JsonSerializer.Serialize(ConfigurationSettings); Properties.Add("configuration", configJson); // Add health check results var healthJson = JsonSerializer.Serialize(HealthChecks); Properties.Add("health_checks", healthJson); base.Build(); } private string GetApplicationVersion() { return Assembly.GetExecutingAssembly().GetName().Version.ToString(); } } // Usage public async Task ReportDatabaseConnectionIssue() { var report = new DiagnosticReport { Component = "Database", Status = "Error", ErrorMessage = "Connection timeout after 30 seconds" }; report.ConfigurationSettings.Add("connection_string", "Server=***;Database=***"); report.ConfigurationSettings.Add("timeout", "30"); report.ConfigurationSettings.Add("retry_count", "3"); report.HealthChecks.Add("database_ping", "Failed"); report.HealthChecks.Add("dns_resolution", "Success"); report.HealthChecks.Add("network_connectivity", "Success"); await _reporting.SendAsync(_userKey, report); }

Añadir información del entorno y del sistema

Puede completar sus informes personalizados con información del entorno y del sistema mediante los recopiladores integrados:

using Babel.Licensing.Reports; using Babel.Licensing.Reports.Collectors; public class EnhancedCustomReport : Report { private readonly EnvironmentReportOptions _envOptions; private readonly SystemReportOptions _sysOptions; public string CustomData { get; set; } public EnhancedCustomReport() : base("EnhancedCustom") { // Configure what environment/system info to collect _envOptions = new EnvironmentReportOptions { CollectApplicationInformation = true, CollectLoadedAssemblies = true, CollectEnvironmentVariables = false }; _sysOptions = new SystemReportOptions { CollectOsInformation = true, CollectProcessorInformation = true, CollectMemoryInformation = true }; } public override void Build() { // Add your custom properties Properties.Add("custom_data", CustomData); // Add environment information var envCollector = new EnvironmentCollector(Properties, _envOptions); envCollector.Collect(); // Add system information var sysCollector = new SystemCollector(Properties, _sysOptions); sysCollector.Collect(); base.Build(); } }

Añadir gráficos a los informes

Los informes personalizados pueden incluir gráficos interactivos que la aplicación web de Babel Licensing muestra automáticamente. Use la clase ReportPlot para crear visualizaciones de los datos de sus informes.

Tipos de gráfico

La enumeración ReportPlotType admite cuatro tipos de gráfico:

  • Pie: muestra datos de distribución en un gráfico circular
  • Line: muestra tendencias a lo largo del tiempo con gráficos de líneas
  • Bar: compara datos por categorías con gráficos de barras
  • Area: representa datos acumulados con gráficos de áreas

Crear un gráfico circular

Los gráficos circulares son idóneos para mostrar la distribución por categorías:

using Babel.Licensing.Reports; // Create a pie chart for attack type distribution var attackDistribution = new ReportPlot(ReportPlotType.Pie, "Attack Type Distribution") .SetHeight(400) .AddSeries("Attacks", new List<object> { new { type = "SQL Injection", count = 45 }, new { type = "XSS", count = 32 }, new { type = "CSRF", count = 18 }, new { type = "Path Traversal", count = 12 }, new { type = "Brute Force", count = 8 } }); // Configure which fields to use for the chart attackDistribution.Series[0].ArgumentField = "type"; // Category labels attackDistribution.Series[0].ValueField = "count"; // Values // Add to report properties Properties.Add("attackDistribution", attackDistribution.ToDictionary());

Crear un gráfico de líneas

Los gráficos de líneas son muy adecuados para mostrar tendencias a lo largo del tiempo:

// Create a line chart comparing attack attempts over time var attackTimeline = new ReportPlot(ReportPlotType.Line, "Attack Attempts Over Time") .SetAxisTitles("Time", "Attack Count") .SetHeight(350) .AddSeries("Today", new List<object> { new { hour = "00:00", attempts = 5 }, new { hour = "04:00", attempts = 3 }, new { hour = "08:00", attempts = 15 }, new { hour = "12:00", attempts = 28 }, new { hour = "16:00", attempts = 22 }, new { hour = "20:00", attempts = 18 } }) .AddSeries("Yesterday", new List<object> { new { hour = "00:00", attempts = 4 }, new { hour = "04:00", attempts = 2 }, new { hour = "08:00", attempts = 12 }, new { hour = "12:00", attempts = 20 }, new { hour = "16:00", attempts = 25 }, new { hour = "20:00", attempts = 15 } }); // Configure field mappings for each series attackTimeline.Series[0].ArgumentField = "hour"; attackTimeline.Series[0].ValueField = "attempts"; attackTimeline.Series[1].ArgumentField = "hour"; attackTimeline.Series[1].ValueField = "attempts"; Properties.Add("attackTimeline", attackTimeline.ToDictionary());

Crear un gráfico de barras

Los gráficos de barras sirven para comparar categorías discretas:

// Create a bar chart for severity levels var severityChart = new ReportPlot(ReportPlotType.Bar, "Attack Severity Levels") .SetAxisTitles("Severity", "Incidents") .SetHeight(350) .AddSeries("Last 24h", new List<object> { new { severity = "Critical", incidents = 8 }, new { severity = "High", incidents = 25 }, new { severity = "Medium", incidents = 42 }, new { severity = "Low", incidents = 30 } }); severityChart.Series[0].ArgumentField = "severity"; severityChart.Series[0].ValueField = "incidents"; Properties.Add("severityChart", severityChart.ToDictionary());

Crear un gráfico de áreas

Los gráficos de áreas son útiles para mostrar datos acumulados de varias series:

// Create an area chart for attack sources by region var ipSourceChart = new ReportPlot(ReportPlotType.Area, "Attack Sources by Region") .SetAxisTitles("Hour", "Unique IPs") .SetHeight(350) .AddSeries("Asia", new List<object> { new { hour = "00:00", ips = 12 }, new { hour = "06:00", ips = 18 }, new { hour = "12:00", ips = 25 }, new { hour = "18:00", ips = 22 } }) .AddSeries("Europe", new List<object> { new { hour = "00:00", ips = 8 }, new { hour = "06:00", ips = 15 }, new { hour = "12:00", ips = 20 }, new { hour = "18:00", ips = 18 } }) .AddSeries("Americas", new List<object> { new { hour = "00:00", ips = 5 }, new { hour = "06:00", ips = 10 }, new { hour = "12:00", ips = 15 }, new { hour = "18:00", ips = 12 } }); // Configure field mappings for all series foreach (var series in ipSourceChart.Series) { series.ArgumentField = "hour"; series.ValueField = "ips"; } Properties.Add("ipSourceChart", ipSourceChart.ToDictionary());

Referencia de la API de ReportPlot

Constructor

new ReportPlot(ReportPlotType type, string title)

Métodos

MétodoDescripción
SetHeight(int height)Establece la altura del gráfico en píxeles
SetAxisTitles(string xAxis, string yAxis)Establece las etiquetas de los ejes X e Y
AddSeries(string name, List<object> data)Añade una serie de datos al gráfico
ToDictionary()Convierte el gráfico en un diccionario para las propiedades del informe

Propiedades de las series

PropiedadDescripción
ArgumentFieldNombre del campo de los objetos de datos que se usa para los valores del eje X (categorías)
ValueFieldNombre del campo de los objetos de datos que se usa para los valores del eje Y (medidas)

Ejemplo completo con varios gráficos

Esta es una clase de informe personalizado completa que incluye varias visualizaciones:

public class SecurityDashboardReport : Report { public SecurityDashboardReport() : base("SecurityDashboard") { } public override void Build() { // Basic properties Properties.Add("generated_at", DateTime.UtcNow); Properties.Add("machine_name", Environment.MachineName); // Pie chart: Attack distribution var attackTypes = new ReportPlot(ReportPlotType.Pie, "Attack Types") .SetHeight(400) .AddSeries("Types", GetAttackTypeData()); attackTypes.Series[0].ArgumentField = "type"; attackTypes.Series[0].ValueField = "count"; Properties.Add("attackTypes", attackTypes.ToDictionary()); // Line chart: Attacks over time var timeline = new ReportPlot(ReportPlotType.Line, "Attack Timeline") .SetAxisTitles("Time", "Attacks") .SetHeight(350) .AddSeries("Attacks", GetTimelineData()); timeline.Series[0].ArgumentField = "time"; timeline.Series[0].ValueField = "count"; Properties.Add("timeline", timeline.ToDictionary()); // Bar chart: Severity breakdown var severity = new ReportPlot(ReportPlotType.Bar, "Severity Distribution") .SetAxisTitles("Level", "Count") .SetHeight(350) .AddSeries("Severity", GetSeverityData()); severity.Series[0].ArgumentField = "level"; severity.Series[0].ValueField = "count"; Properties.Add("severity", severity.ToDictionary()); base.Build(); } private List<object> GetAttackTypeData() => new List<object> { new { type = "SQL Injection", count = 45 }, new { type = "XSS", count = 32 }, new { type = "CSRF", count = 18 } }; private List<object> GetTimelineData() => new List<object> { new { time = "08:00", count = 15 }, new { time = "12:00", count = 28 }, new { time = "16:00", count = 22 } }; private List<object> GetSeverityData() => new List<object> { new { level = "Critical", count = 8 }, new { level = "High", count = 25 }, new { level = "Medium", count = 42 } }; }

Cuando este informe se abre en la aplicación web de Babel Licensing, todos los gráficos se muestran como visualizaciones interactivas, lo que permite analizar visualmente los datos del informe personalizado.

Cifrado de informes

Proteja con cifrado los datos confidenciales de sus informes personalizados:

var reporting = new BabelReporting(); reporting.Configuration.EncryptionKey = "your-secret-encryption-key"; var report = new SecurityEventReport { EventType = "DataBreach", Severity = "Critical", // ... sensitive data }; // Report will be automatically encrypted before transmission var result = await reporting.SendAsync(userKey, report);

Para descifrar el informe, el servidor debe estar configurado con la misma clave de cifrado.

Personalizar antes del envío

Modifique cualquier informe (incluidos los personalizados) antes de enviarlo:

reporting.BeforeSendReport += (s, e) => { // Add global properties to all reports e.Report.Properties.Add("environment", "production"); e.Report.Properties.Add("region", "us-east-1"); e.Report.Properties.Add("deployment_id", DeploymentId); // Add conditional logic if (e.Report.Name == "SecurityEvent") { e.Report.Properties.Add("security_version", SecurityFrameworkVersion); } // Validate before sending if (!IsValidReport(e.Report)) { e.Cancel = true; // Don't send invalid reports } };

Estructura del informe

Todos los informes siguen la misma estructura JSON:

{ "name": "HackDetection", "version": "1.0", "date": "2025-01-22T10:30:00Z", "encrypted": false, "content": { "properties": { "machine_name": "DESKTOP-ABC123", "hacking_type": "SQL Injection", "attack_method": "Malicious Input", "detection_details": "Detected SQL keywords in user input", "detected_at": "2025-01-22T10:30:00Z" } } }

Procesamiento en el servidor

Cuando su informe personalizado llega al Babel Licensing Service:

  1. Validación: se validan el nombre y el contenido del informe
  2. Descifrado: el contenido cifrado se descifra con la clave configurada
  3. Análisis sintáctico: se extraen las propiedades del contenido
  4. Almacenamiento: el informe se guarda en la base de datos con sus metadatos
  5. Indexación: las propiedades se indexan para poder buscarlas
  6. Webhooks: se envían eventos ReportCreated para las integraciones externas

Puede consultar los informes personalizados mediante la API del Babel Licensing Service:

GET /api/reports?name=HackDetection&from=2025-01-01&to=2025-01-31

Prácticas recomendadas

1. Elegir nombres de informe descriptivos

Use nombres descriptivos y coherentes para sus tipos de informe:

// GOOD: Clear and specific public class UserAuthenticationFailureReport : Report { public UserAuthenticationFailureReport() : base("UserAuthFailure") { } } // BAD: Generic and unclear public class CustomReport1 : Report { public CustomReport1() : base("Report1") { } }

2. Incluir marcas de tiempo

Incluya siempre marcas de tiempo para el análisis temporal:

public override void Build() { Properties.Add("timestamp", DateTime.UtcNow); Properties.Add("event_time", eventOccurredAt); base.Build(); }

3. Añadir información de contexto

Incluya contexto suficiente para que se pueda actuar a partir del informe:

Properties.Add("user_id", userId); Properties.Add("session_id", sessionId); Properties.Add("request_id", requestId); Properties.Add("correlation_id", correlationId);

4. Usar datos estructurados

Prefiera los datos estructurados al texto libre para facilitar el análisis:

// GOOD: Structured Properties.Add("response_time_ms", 1250); Properties.Add("status_code", 200); Properties.Add("endpoint", "/api/users"); // BAD: Unstructured Properties.Add("message", "Request to /api/users took 1250ms and returned 200");

5. Gestionar los errores de forma controlada

No deje que los fallos de los informes afecten al funcionamiento de la aplicación:

try { var report = new CustomReport { /* ... */ }; await _reporting.SendAsync(_userKey, report); } catch (Exception ex) { // Log error but don't throw _logger.LogWarning(ex, "Failed to send custom report"); }

En lugar de enviar muchos informes individuales, agrupe los eventos relacionados:

public class BatchEventReport : Report { public List<EventData> Events { get; set; } = new List<EventData>(); public BatchEventReport() : base("BatchEvent") { } public override void Build() { Properties.Add("event_count", Events.Count); Properties.Add("events", JsonSerializer.Serialize(Events)); Properties.Add("batch_time", DateTime.UtcNow); base.Build(); } }

7. Sanear los datos confidenciales

No incluya nunca contraseñas, claves API ni información de identificación personal:

public override void Build() { // GOOD: Sanitized Properties.Add("username", SanitizeUsername(username)); Properties.Add("email", HashEmail(email)); // BAD: Sensitive data // Properties.Add("password", password); // NEVER DO THIS // Properties.Add("credit_card", cardNumber); // NEVER DO THIS base.Build(); } private string SanitizeUsername(string username) { // Return first 3 chars + asterisks if (username.Length <= 3) return "***"; return username.Substring(0, 3) + new string('*', username.Length - 3); }

Ejemplo completo

Este es un ejemplo completo que combina informes personalizados con un control de errores y una configuración adecuados:

using Babel.Licensing.Reports; using Babel.Licensing.Services; using Microsoft.Extensions.Logging; public class ApplicationReportingService { private readonly BabelReporting _reporting; private readonly ILogger<ApplicationReportingService> _logger; private readonly string _userKey; public ApplicationReportingService( IConfiguration configuration, ILogger<ApplicationReportingService> logger) { _logger = logger; _userKey = configuration["Licensing:UserKey"]; _reporting = new BabelReporting(); _reporting.Configuration.ServiceUrl = configuration["Licensing:ServiceUrl"]; _reporting.Configuration.ClientId = "EquiTrack v2.0"; _reporting.Configuration.EncryptionKey = configuration["Licensing:EncryptionKey"]; _reporting.BeforeSendReport += OnBeforeSendReport; _reporting.AfterSendReport += OnAfterSendReport; } private void OnBeforeSendReport(object sender, BeforeSendReportEventArgs e) { // Add global context to all reports e.Report.Properties["application_version"] = GetApplicationVersion(); e.Report.Properties["environment"] = GetEnvironment(); } private void OnAfterSendReport(object sender, AfterSendReportEventArgs e) { if (e.Error != null) { _logger.LogError(e.Error, "Failed to send {ReportType} report", e.Report.Name); } else { _logger.LogInformation("Sent {ReportType} report: {ReportId}", e.Report.Name, e.Result.ReportUid); } } public async Task ReportSecurityEvent( string eventType, string severity, string details) { try { var report = new SecurityEventReport { EventType = eventType, Severity = severity, SourceIP = GetClientIpAddress(), UserAgent = GetUserAgent(), RequestPath = GetCurrentRequestPath() }; report.AdditionalData["details"] = details; var result = await _reporting.SendAsync(_userKey, report); if (!result.Success) { _logger.LogWarning("Security event report failed: {Error}", result.Error?.Message); } } catch (Exception ex) { _logger.LogError(ex, "Exception sending security event report"); } } private string GetApplicationVersion() => Assembly.GetExecutingAssembly().GetName().Version.ToString(); private string GetEnvironment() => Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"; private string GetClientIpAddress() => /* implementation */; private string GetUserAgent() => /* implementation */; private string GetCurrentRequestPath() => /* implementation */; }
Last updated on