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.gitIn das Projektverzeichnis wechseln
Wechseln Sie nach dem Klonen des Repositorys in das Projektverzeichnis:
cd console-custom-report-exampleBeispiel 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:
- 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;
}-
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. -
Benutzerdefinierte Berichtsklasse: Die Klasse
HackDetectionReporterbt vonReportund definiert benutzerdefinierte Eigenschaften, mit denen Sicherheitsereignisse erfasst werden. Sie verwendetReportPlot, 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();
}
}-
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 wiecmdline(Befehlszeile) undusername(Name des aktuellen Benutzers) hinzugefügt. -
Senden des Berichts: Die Methode
SendAsyncsendet 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
| Methode | Beschreibung |
|---|---|
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
| Eigenschaft | Beschreibung |
|---|---|
ArgumentField | Name des Felds in den Datenobjekten, das die Werte der X-Achse liefert (Kategorien) |
ValueField | Name 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:
- Validierung: Name und Inhalt des Berichts werden validiert
- Entschlüsselung: Verschlüsselte Inhalte werden mit dem konfigurierten Schlüssel entschlüsselt
- Parsen: Die Eigenschaften werden aus dem Inhalt extrahiert
- Speicherung: Der Bericht wird mit seinen Metadaten in der Datenbank gespeichert
- Indizierung: Die Eigenschaften werden indiziert, damit sie durchsuchbar sind
- Webhooks: Ereignisse vom Typ
ReportCreatedwerden 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-31Bewä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");
}6. Zusammengehörige Ereignisse bündeln
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 */;
}Verwandte Themen
- Fehlerberichte: integrierte Fehlerberichte
- Lizenznutzungsberichte: die Lizenznutzung erfassen
- Floating-Lizenz: Benutzerschlüssel für das Reporting erzeugen