Skip to Content
Neue Version 12 verfügbar 🎉
LicensingReportingBenutzerdefinierte Berichte

Benutzerdefinierte Berichte

Neben den integrierten Fehlerberichten und Lizenznutzungsberichten können Sie mit Babel Licensing benutzerdefinierte Berichte erstellen, die auf die Anforderungen Ihrer Anwendung zugeschnitten sind. Mit benutzerdefinierten Berichten senden Sie beliebige strukturierte Daten an Ihren Babel Licensing Service, wo sie zentral gesammelt, ausgewertet und überwacht werden.

Übersicht

Benutzerdefinierte Berichte eignen sich für:

  • Sicherheitsereignisse: mögliche Angriffsversuche, unbefugte Zugriffe oder verdächtiges Verhalten erkennen und melden
  • Anwendungskennzahlen: eigene Kennzahlen zur Leistung oder Nutzung der Anwendung erfassen
  • Geschäftsereignisse: wichtige Geschäftsereignisse oder Meilensteine melden
  • Diagnose: eigene Diagnosedaten für die Fehlerbehebung senden
  • Audit-Trails: Audit-Protokolle für Compliance-Anforderungen erstellen

Beispiel einer Konsolenanwendung

Für den Einstieg mit einem praktischen Beispiel klonen Sie das Repository console-custom-report-example. Es zeigt, wie Sie mit den Reporting-Funktionen von Babel benutzerdefinierte Berichte erstellen und senden.

Git-Client öffnen

Öffnen Sie Ihren bevorzugten Git-Client oder die Befehlszeile.

Repository klonen

Klonen Sie das GitHub-Repository mit dem folgenden Befehl:

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

Wechseln Sie nach dem Klonen des Repositorys in das Projektverzeichnis:

cd console-custom-report-example

Beispiel erkunden und ausführen

Jetzt können Sie den Beispielcode erkunden und ausführen.

Das Beispiel console-custom-report-example zeigt, wie Sie die Clientbibliothek von Babel Licensing in Ihre Anwendung integrieren, um benutzerdefinierte Berichte zu erstellen und an den Babel Licensing Service zu senden. Der Code im Einzelnen:

  1. Initialisierung von BabelReporting: Der Beispielcode initialisiert ein BabelReporting-Objekt und konfiguriert es mit der URL des Dienstes und der Client-ID.
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. Benutzerschlüssel: Der Beispielcode verwendet einen Benutzerschlüssel (UserKey), der den Client zum Senden von Berichten autorisiert. Ersetzen Sie ihn durch einen gültigen Benutzerschlüssel. Wie Sie einen Benutzerschlüssel erzeugen, lesen Sie in den Abschnitten Floating-Lizenz oder Lizenzaktivierung.

  2. Benutzerdefinierte Berichtsklasse: Die Klasse HackDetectionReport erbt von Report und definiert benutzerdefinierte Eigenschaften, mit denen Sicherheitsereignisse erfasst werden. Sie verwendet ReportPlot, um interaktive Diagramme zu erstellen, die in der Webanwendung dargestellt werden:

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. Ereignis BeforeSendReport: Das Beispiel abonniert das Ereignis BeforeSendReport, mit dem Sie Berichten vor dem Senden weitere Eigenschaften hinzufügen können. In diesem Ereignishandler werden benutzerdefinierte Eigenschaften wie cmdline (Befehlszeile) und username (Name des aktuellen Benutzers) hinzugefügt.

  2. Senden des Berichts: Die Methode SendAsync sendet den benutzerdefinierten Bericht an den 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."); }

Beispiel eines benutzerdefinierten Berichts

Das Beispiel console-custom-report-example zeigt in der Praxis, wie Sie benutzerdefinierte Berichtstypen erstellen und an den Babel Licensing Service senden. Wenn Sie benutzerdefinierte Berichte in Ihre Anwendungen integrieren, können Sie Sicherheitsereignisse, Anwendungskennzahlen, Geschäftsereignisse und alle weiteren strukturierten Daten erfassen, die für Ihre Anwendung von Bedeutung sind.

Einen benutzerdefinierten Bericht erstellen

Um einen benutzerdefinierten Bericht zu erstellen, leiten Sie eine Klasse von der Basisklasse Report ab:

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(); } }

Die Basisklasse Report

Die Klasse Report bildet die Grundlage aller Berichte:

Wichtige Eigenschaften

  • Name: eindeutiger Bezeichner des Berichtstyps (zum Beispiel „HackDetection“, „PerformanceMetrics“)
  • Content: als JSON serialisierte Berichtsdaten (von Build() erzeugt)
  • Version: Version des Berichtsformats (derzeit „1.0“)
  • Date: Zeitstempel der Berichtserstellung
  • Encrypted: Flag, das angibt, ob der Inhalt verschlüsselt ist
  • Properties: Wörterbuch für benutzerdefinierte Schlüssel-Wert-Daten

Wichtige Methoden

  • Build(): Überschreiben Sie diese Methode, um Ihre benutzerdefinierten Eigenschaften zu füllen
  • Create(string report, string password): deserialisiert einen Bericht aus JSON
  • FromException(Exception ex, ExceptionReportOptions options): Factory-Methode für Fehlerberichte

Benutzerdefinierte Berichte senden

Wenn Sie Ihre benutzerdefinierte Berichtsklasse erstellt haben, senden Sie den Bericht mit 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}"); }

Beispiele aus der Praxis

Beispiel 1: Bericht über Sicherheitsereignisse

Erkennen und melden Sie mögliche Sicherheitsbedrohungen:

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); }

Beispiel 2: Bericht über Leistungskennzahlen

Erfassen Sie Leistungskennzahlen der Anwendung:

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)); } }

Beispiel 3: Bericht über Geschäftsereignisse

Erfassen Sie wichtige Geschäftsereignisse:

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); }

Beispiel 4: Diagnosebericht

Senden Sie ausführliche Diagnoseinformationen:

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); }

Umgebungs- und Systeminformationen hinzufügen

Mit den integrierten Sammlern können Sie Ihre benutzerdefinierten Berichte um Umgebungs- und Systeminformationen ergänzen:

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(); } }

Diagramme zu Berichten hinzufügen

Benutzerdefinierte Berichte können interaktive Diagramme enthalten, die die Webanwendung von Babel Licensing automatisch darstellt. Mit der Klasse ReportPlot erstellen Sie Visualisierungen Ihrer Berichtsdaten.

Diagrammtypen

Die Enumeration ReportPlotType unterstützt vier Diagrammtypen:

  • Pie: stellt Verteilungen als Kreisdiagramm dar
  • Line: zeigt Trends über die Zeit als Liniendiagramm
  • Bar: vergleicht kategoriale Daten als Balkendiagramm
  • Area: veranschaulicht kumulierte Daten als Flächendiagramm

Ein Kreisdiagramm erstellen

Kreisdiagramme eignen sich besonders, um die Verteilung auf Kategorien zu zeigen:

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());

Ein Liniendiagramm erstellen

Liniendiagramme eignen sich sehr gut, um Trends über die Zeit zu zeigen:

// 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());

Ein Balkendiagramm erstellen

Balkendiagramme eignen sich gut für den Vergleich einzelner Kategorien:

// 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());

Ein Flächendiagramm erstellen

Flächendiagramme sind nützlich, um kumulierte Daten über mehrere Datenreihen hinweg zu zeigen:

// 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());

API-Referenz von ReportPlot

Konstruktor

new ReportPlot(ReportPlotType type, string title)

Methoden

MethodeBeschreibung
SetHeight(int height)Legt die Höhe des Diagramms in Pixeln fest
SetAxisTitles(string xAxis, string yAxis)Legt die Beschriftungen der X- und der Y-Achse fest
AddSeries(string name, List<object> data)Fügt dem Diagramm eine Datenreihe hinzu
ToDictionary()Wandelt das Diagramm in ein Wörterbuch für die Eigenschaften des Berichts um

Eigenschaften der Datenreihen

EigenschaftBeschreibung
ArgumentFieldName des Felds in den Datenobjekten, das die Werte der X-Achse liefert (Kategorien)
ValueFieldName des Felds in den Datenobjekten, das die Werte der Y-Achse liefert (Messwerte)

Vollständiges Beispiel mit mehreren Diagrammen

Die folgende vollständige Klasse eines benutzerdefinierten Berichts enthält mehrere Visualisierungen:

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 } }; }

Wenn Sie diesen Bericht in der Webanwendung von Babel Licensing ansehen, werden alle Diagramme als interaktive Visualisierungen dargestellt, sodass Sie die Daten Ihres benutzerdefinierten Berichts visuell auswerten können.

Berichtsverschlüsselung

Schützen Sie sensible Daten in Ihren benutzerdefinierten Berichten durch Verschlüsselung:

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);

Der Server muss mit demselben Verschlüsselungsschlüssel konfiguriert sein, damit er den Bericht entschlüsseln kann.

Vor dem Senden anpassen

Ändern Sie einen beliebigen Bericht (auch einen benutzerdefinierten), bevor er gesendet wird:

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 } };

Struktur der Berichte

Alle Berichte folgen einer einheitlichen JSON-Struktur:

{ "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" } } }

Serverseitige Verarbeitung

Wenn Ihr benutzerdefinierter Bericht beim Babel Licensing Service eintrifft, geschieht Folgendes:

  1. Validierung: Name und Inhalt des Berichts werden validiert
  2. Entschlüsselung: Verschlüsselte Inhalte werden mit dem konfigurierten Schlüssel entschlüsselt
  3. Parsen: Die Eigenschaften werden aus dem Inhalt extrahiert
  4. Speicherung: Der Bericht wird mit seinen Metadaten in der Datenbank gespeichert
  5. Indizierung: Die Eigenschaften werden indiziert, damit sie durchsuchbar sind
  6. Webhooks: Ereignisse vom Typ ReportCreated werden für externe Integrationen gesendet

Benutzerdefinierte Berichte können Sie über die API des Babel Licensing Service abfragen:

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

Bewährte Vorgehensweisen

1. Aussagekräftige Berichtsnamen wählen

Verwenden Sie beschreibende, einheitliche Namen für Ihre Berichtstypen:

// 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. Zeitstempel aufnehmen

Nehmen Sie immer Zeitstempel auf, damit eine zeitliche Auswertung möglich ist:

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

3. Kontextinformationen hinzufügen

Geben Sie genug Kontext an, damit sich aus dem Bericht Maßnahmen ableiten lassen:

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

4. Strukturierte Daten verwenden

Ziehen Sie strukturierte Daten freiem Text vor, weil sie sich besser auswerten lassen:

// 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. Fehler sauber abfangen

Fehler beim Senden von Berichten dürfen die Funktion der Anwendung nicht beeinträchtigen:

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"); }

Senden Sie nicht viele einzelne Berichte, sondern bündeln Sie zusammengehörige Ereignisse:

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. Sensible Daten bereinigen

Nehmen Sie niemals Passwörter, API-Schlüssel oder personenbezogene Daten auf:

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); }

Vollständiges Beispiel

Das folgende vollständige Beispiel verbindet benutzerdefinierte Berichte mit einer sauberen Fehlerbehandlung und Konfiguration:

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