From 2a6b68ba6d324d6bddaa0be418586727f63a1a18 Mon Sep 17 00:00:00 2001 From: Dave Friedel Date: Fri, 26 Dec 2025 06:14:09 -0500 Subject: [PATCH] UserJourney --- IronTelemetry.Client.csproj | 8 +++ IronTelemetry.cs | 50 ++++++++++++++++++ TelemetryClient.cs | 101 ++++++++++++++++++++++-------------- nuget_it.png | Bin 0 -> 3045 bytes 4 files changed, 120 insertions(+), 39 deletions(-) create mode 100644 nuget_it.png diff --git a/IronTelemetry.Client.csproj b/IronTelemetry.Client.csproj index 15fe789..739b20b 100644 --- a/IronTelemetry.Client.csproj +++ b/IronTelemetry.Client.csproj @@ -5,6 +5,7 @@ enable enable true + C:\Users\logik\Dropbox\Nugets IronTelemetry.Client @@ -17,6 +18,7 @@ https://github.com/ironservices/irontelemetry-client https://www.irontelemetry.com README.md + nuget_it.png @@ -24,6 +26,12 @@ + + true + \ + PreserveNewest + true + diff --git a/IronTelemetry.cs b/IronTelemetry.cs index db8ac6c..10f6dc7 100644 --- a/IronTelemetry.cs +++ b/IronTelemetry.cs @@ -1,3 +1,5 @@ +using System.Diagnostics; + namespace IronTelemetry.Client; /// @@ -9,6 +11,31 @@ public static class IronTelemetry { private static TelemetryClient? _client; private static readonly object _lock = new(); + private static bool _enableDebugLogging; + + /// + /// Enable verbose debug output during development. + /// When enabled, all events are written to System.Diagnostics.Debug.WriteLine. + /// + /// + /// IronTelemetry.EnableDebugLogging = true; // Enable during development + /// + public static bool EnableDebugLogging + { + get => _enableDebugLogging; + set => _enableDebugLogging = value; + } + + /// + /// Writes a debug message if EnableDebugLogging is true. + /// + internal static void DebugLog(string message) + { + if (_enableDebugLogging) + { + Debug.WriteLine($"[IronTelemetry] {message}"); + } + } /// /// Initialize IronTelemetry with a DSN. @@ -61,6 +88,29 @@ public static class IronTelemetry _client!.CaptureMessage(message, level); } + /// + /// Log a message with a title, message, and optional metadata. + /// This is useful for debugging and informational logging without exceptions. + /// + /// Log level: "info", "warning", "error", "debug" + /// Short title for the log entry + /// Detailed message (optional) + /// Optional additional data + public static void LogMessage(string level, string title, string? message = null, Dictionary? data = null) + { + EnsureInitialized(); + _client!.LogMessage(level, title, message, data); + } + + /// + /// Get all current breadcrumbs. Useful for viewing breadcrumbs in a debug UI. + /// + public static IReadOnlyList GetBreadcrumbs() + { + EnsureInitialized(); + return _client!.GetBreadcrumbs(); + } + /// /// Add a breadcrumb to the current context. /// diff --git a/TelemetryClient.cs b/TelemetryClient.cs index b7e569f..675a027 100644 --- a/TelemetryClient.cs +++ b/TelemetryClient.cs @@ -1,4 +1,5 @@ using System.Collections.Concurrent; +using System.Diagnostics; using System.Net.Http.Json; using System.Runtime.InteropServices; using System.Text.Json; @@ -127,7 +128,7 @@ public class TelemetryClient : IDisposable StepId = currentStep?.StepId, TraceId = context?.TraceId, SpanId = context?.SpanId, - Breadcrumbs = GetBreadcrumbs(), + Breadcrumbs = GetBreadcrumbPayloads(), Metadata = MergeMetadata(context?.Extras, currentJourney?.Metadata) }; @@ -143,23 +144,43 @@ public class TelemetryClient : IDisposable _pendingItems.Enqueue(item); AddToLocalLog(item); - if (_options.Debug) - { - var journeyInfo = currentJourney != null ? $" (journey: {currentJourney.Name})" : ""; - Console.WriteLine($"[IronTelemetry] Captured exception: {ex.GetType().Name}: {ex.Message}{journeyInfo}"); - } + var journeyInfo = currentJourney != null ? $" (journey: {currentJourney.Name})" : ""; + LogDebug($"Captured exception: {ex.GetType().Name}: {ex.Message}{journeyInfo}"); } public void CaptureMessage(string message, TelemetryLevel level) + { + LogMessage(level.ToString(), message, null, null); + } + + /// + /// Log a message with a title, message, and optional metadata. + /// This is useful for debugging and informational logging without exceptions. + /// + /// Log level: "info", "warning", "error", "debug" + /// Short title for the log entry + /// Detailed message + /// Optional additional data + public void LogMessage(string level, string title, string? message = null, Dictionary? data = null) { var currentJourney = JourneyContext.Current; var currentStep = JourneyContext.CurrentStep; + var metadata = new Dictionary(_extras); + if (data != null) + { + foreach (var kvp in data) + { + metadata[kvp.Key] = kvp.Value; + } + } + var item = new EnvelopeItem { Type = "message", - ExceptionType = level.ToString(), - Message = message, + ExceptionType = level, + Name = title, + Message = message ?? title, AppVersion = _options.AppVersion, AppBuild = _options.AppBuild, Environment = _options.Environment, @@ -167,12 +188,14 @@ public class TelemetryClient : IDisposable UserEmail = currentJourney?.UserEmail ?? _userEmail, JourneyId = currentJourney?.JourneyId, StepId = currentStep?.StepId, - Breadcrumbs = GetBreadcrumbs(), - Metadata = new Dictionary(_extras) + Breadcrumbs = GetBreadcrumbPayloads(), + Metadata = metadata }; _pendingItems.Enqueue(item); AddToLocalLog(item); + + LogDebug($"[{level.ToUpperInvariant()}] {title}: {message}"); } public void AddBreadcrumb(Breadcrumb breadcrumb) @@ -234,10 +257,7 @@ public class TelemetryClient : IDisposable _pendingItems.Enqueue(item); AddToLocalLog(item); - if (_options.Debug) - { - Console.WriteLine($"[IronTelemetry] Started journey: {journey.Name} ({journey.JourneyId})"); - } + LogDebug($"Started journey: {journey.Name} ({journey.JourneyId})"); } internal void EnqueueJourneyEnd(JourneyScope journey) @@ -256,10 +276,7 @@ public class TelemetryClient : IDisposable _pendingItems.Enqueue(item); AddToLocalLog(item); - if (_options.Debug) - { - Console.WriteLine($"[IronTelemetry] Ended journey: {journey.Name} ({journey.Status})"); - } + LogDebug($"Ended journey: {journey.Name} ({journey.Status})"); } internal void EnqueueStepStart(StepScope step, string journeyId) @@ -277,10 +294,7 @@ public class TelemetryClient : IDisposable _pendingItems.Enqueue(item); AddToLocalLog(item); - if (_options.Debug) - { - Console.WriteLine($"[IronTelemetry] Started step: {step.Name}"); - } + LogDebug($"Started step: {step.Name}"); } internal void EnqueueStepEnd(StepScope step, string journeyId) @@ -304,10 +318,7 @@ public class TelemetryClient : IDisposable _pendingItems.Enqueue(item); AddToLocalLog(item); - if (_options.Debug) - { - Console.WriteLine($"[IronTelemetry] Ended step: {step.Name} ({step.Status})"); - } + LogDebug($"Ended step: {step.Name} ({step.Status})"); } #endregion @@ -349,10 +360,7 @@ public class TelemetryClient : IDisposable // Queue for retry _offlineQueue.Enqueue(items); - if (_options.Debug) - { - Console.WriteLine($"[IronTelemetry] Queued {items.Count} items for offline retry"); - } + LogDebug($"Queued {items.Count} items for offline retry"); } } finally @@ -373,19 +381,13 @@ public class TelemetryClient : IDisposable var response = await _httpClient.PostAsJsonAsync(url, envelope, JsonOptions); - if (_options.Debug) - { - Console.WriteLine($"[IronTelemetry] Sent {items.Count} items, status: {response.StatusCode}"); - } + LogDebug($"Sent {items.Count} items, status: {response.StatusCode}"); return response.IsSuccessStatusCode; } catch (Exception ex) { - if (_options.Debug) - { - Console.WriteLine($"[IronTelemetry] Failed to send: {ex.Message}"); - } + LogDebug($"Failed to send: {ex.Message}"); return false; } } @@ -421,7 +423,12 @@ public class TelemetryClient : IDisposable return true; } - private List GetBreadcrumbs() + /// + /// Get all current breadcrumbs. Useful for viewing breadcrumbs in a debug UI. + /// + public IReadOnlyList GetBreadcrumbs() => _breadcrumbs.ToArray(); + + private List GetBreadcrumbPayloads() { return _breadcrumbs.Select(b => new BreadcrumbPayload { @@ -488,6 +495,22 @@ public class TelemetryClient : IDisposable return (baseUrl, publicKey); } + + /// + /// Write a debug log message. Uses Debug.WriteLine if EnableDebugLogging is set, + /// otherwise Console.WriteLine if options.Debug is set. + /// + private void LogDebug(string message) + { + if (IronTelemetry.EnableDebugLogging) + { + Debug.WriteLine($"[IronTelemetry] {message}"); + } + else if (_options.Debug) + { + Console.WriteLine($"[IronTelemetry] {message}"); + } + } } /// diff --git a/nuget_it.png b/nuget_it.png new file mode 100644 index 0000000000000000000000000000000000000000..fec39600b65b94284f4ba04a6152ac6b28e2e457 GIT binary patch literal 3045 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