[변경] AptabaseClient.cs
- 종료 직전에 보내는 Event 누락 방지하기 위한 코드 수정 : 큐에 이벤트를 추가하면 +1, 큐에서 읽어와서 Event를 Send하면 -1하는 필드 추가 : 필드가 0이되기를 기다리는 함수 추가(대기 한계 시간 기본값 1500ms) [변경] AptabaseClientBase.cs - EventData에 ipAddredd 할당하는 코드 제거 : 매번 API 호출하면서 속도 지연의 원인이 됨 - aptabase-debug.log 파일 생성하는 코드 제거 : 파일 관리가 안되고 있으므로 제거
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Threading.Channels;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Aptabase.WPF;
|
||||
|
||||
@@ -10,6 +11,10 @@ public class AptabaseClient : IAptabaseClient
|
||||
private Task? _processingTask;
|
||||
private AptabaseClientBase? _client;
|
||||
private CancellationTokenSource? _cts;
|
||||
private ILogger? _logger;
|
||||
private int _queueItemCount = 0;
|
||||
|
||||
public bool IsRunning => _processingTask != null && !_processingTask.IsCompleted;
|
||||
|
||||
public AptabaseClient(string appKey, AptabaseOptions? options, ILogger? logger)
|
||||
{
|
||||
@@ -20,30 +25,44 @@ public class AptabaseClient : IAptabaseClient
|
||||
{
|
||||
_client = new AptabaseClientBase(appKey, options, logger);
|
||||
_channel = Channel.CreateUnbounded<EventData>();
|
||||
_processingTask = Task.Run(ProcessEventsAsync);
|
||||
_cts = new CancellationTokenSource();
|
||||
_processingTask = Task.Run(() => ProcessEventsAsync(_cts.Token));
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public Task TrackEvent(string eventName, Dictionary<string, object>? props = null)
|
||||
public async Task TrackEvent(string eventName, Dictionary<string, object>? props = null)
|
||||
{
|
||||
_channel?.Writer.TryWrite(new EventData(eventName, props));
|
||||
|
||||
return Task.CompletedTask;
|
||||
try
|
||||
{
|
||||
if (_channel != null)
|
||||
{
|
||||
await _channel.Writer.WriteAsync(new EventData(eventName, props));
|
||||
Interlocked.Increment(ref _queueItemCount);
|
||||
Debug.WriteLine($"Queued event {eventName} to Aptabase {_queueItemCount}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger?.LogError(ex, "Error queueing event {EventName} to Aptabase", eventName);
|
||||
Console.WriteLine(ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ProcessEventsAsync()
|
||||
private async Task ProcessEventsAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_channel is null || _cts is null || _client is null)
|
||||
{
|
||||
Interlocked.CompareExchange(ref _queueItemCount, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
while (await _channel.Reader.WaitToReadAsync())
|
||||
while (await _channel.Reader.WaitToReadAsync(cancellationToken))
|
||||
{
|
||||
if (_cts.IsCancellationRequested)
|
||||
{
|
||||
Interlocked.CompareExchange(ref _queueItemCount, 0, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -51,23 +70,30 @@ public class AptabaseClient : IAptabaseClient
|
||||
{
|
||||
if (_cts.IsCancellationRequested)
|
||||
{
|
||||
Interlocked.CompareExchange(ref _queueItemCount, 0, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await _client.TrackEvent(eventData);
|
||||
Interlocked.Decrement(ref _queueItemCount);
|
||||
Debug.WriteLine($"Sent event {eventData.EventName} to Aptabase {eventData.Timestamp} / {_queueItemCount}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger?.LogError(ex, "Error sending event {EventName} to Aptabase", eventData.EventName);
|
||||
Console.WriteLine(ex.ToString());
|
||||
Debug.WriteLine($"Error sending event {eventData.EventName} to Aptabase: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ChannelClosedException)
|
||||
catch (ChannelClosedException ex)
|
||||
{
|
||||
// ignore
|
||||
Interlocked.CompareExchange(ref _queueItemCount, 0, 0);
|
||||
_logger?.LogError(ex, "Channel closed unexpectedly");
|
||||
Debug.WriteLine($"Channel closed unexpectedly: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,4 +120,18 @@ public class AptabaseClient : IAptabaseClient
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public async Task StopAsync(int timeoutMs = 1500)
|
||||
{
|
||||
_channel?.Writer.Complete();
|
||||
|
||||
var sw = Stopwatch.StartNew();
|
||||
while (Volatile.Read(ref _queueItemCount) > 0 && sw.ElapsedMilliseconds < timeoutMs)
|
||||
{
|
||||
await Task.Delay(100); // 큐가 비워질 때까지 대기
|
||||
}
|
||||
|
||||
if (_processingTask is { IsCompleted: false })
|
||||
await Task.WhenAny(_processingTask, Task.Delay(timeoutMs)); // 드레인 대기 (타임아웃 허용)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,13 +73,13 @@ internal class AptabaseClientBase : IAsyncDisposable
|
||||
if (eventData.Props is null)
|
||||
eventData.Props = new Dictionary<string, object>();
|
||||
|
||||
eventData.Props["ipAddress"] = await GetPublicIpAddress();
|
||||
//eventData.Props["ipAddress"] = await GetPublicIpAddress(); 느려서 제외. 필요하면 다른 방법 사용 요망
|
||||
|
||||
var body = JsonContent.Create(eventData);
|
||||
|
||||
var response = await _http.PostAsync("/api/v0/event", body);
|
||||
|
||||
var logPath = "aptabase-debug.log";
|
||||
//var logPath = "aptabase-debug.log"; //파일 관리 안되므로 제거. 필요하면 다른 방법 사용 요망
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
@@ -94,11 +94,11 @@ internal class AptabaseClientBase : IAsyncDisposable
|
||||
var responseBody = await response.Content.ReadAsStringAsync();
|
||||
|
||||
_logger?.LogError("Failed to perform TrackEvent due to {StatusCode} and response body {Body}", response.StatusCode, responseBody);
|
||||
File.AppendAllText(logPath, $"Failed to perform TrackEvent due to {response.StatusCode} and response body {responseBody}\n");
|
||||
//File.AppendAllText(logPath, $"{eventData.EventName} Failed to perform TrackEvent due to {response.StatusCode} and response body {responseBody}\n");
|
||||
}
|
||||
else
|
||||
{ var responseBody = await response.Content.ReadAsStringAsync();
|
||||
File.AppendAllText(logPath, $"TrackEvent successful with response body {responseBody}\n");
|
||||
//File.AppendAllText(logPath, $"{eventData.EventName} TrackEvent successful with response body {responseBody}\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user