welsonjs/WelsonJS.Toolkit/WelsonJS.Launcher/Telemetry/PosthogTelemetryProvider.cs
Namhyeon, Go 1d4b7af5b3 Fix the logger for telemetry
Fix the logger for telemetry
2025-12-03 16:54:19 +09:00

95 lines
3.1 KiB
C#

// PosthogTelemetryProvider.cs
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2025 Catswords OSS and WelsonJS Contributors
// https://github.com/gnh1201/welsonjs
//
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace WelsonJS.Launcher.Telemetry
{
public sealed class PosthogTelemetryProvider : ITelemetryProvider, IDisposable
{
private readonly TelemetryOptions _options;
private readonly HttpClient _httpClient;
private readonly ICompatibleLogger _logger;
private bool _disposed;
public PosthogTelemetryProvider(TelemetryOptions options, ICompatibleLogger logger = null)
{
_options = options ?? throw new ArgumentNullException(nameof(options));
if (!_options.Disabled)
{
if (string.IsNullOrWhiteSpace(_options.ApiKey))
throw new ArgumentException("PostHog API key is missing.");
if (string.IsNullOrWhiteSpace(_options.BaseUrl))
throw new ArgumentException("PostHog BaseUrl is missing.");
}
if (string.IsNullOrWhiteSpace(_options.DistinctId))
_options.DistinctId = $"anon-{Guid.NewGuid():N}";
_httpClient = new HttpClient { Timeout = TimeSpan.FromSeconds(5) };
_logger = logger;
}
public async Task TrackEventAsync(
string eventName,
IDictionary<string, object> properties = null,
CancellationToken cancellationToken = default)
{
if (_disposed) throw new ObjectDisposedException(nameof(PosthogTelemetryProvider));
if (_options.Disabled) return;
if (string.IsNullOrWhiteSpace(eventName))
return;
string json;
using (var ser = new JsSerializer())
{
var payload = new Dictionary<string, object>
{
["api_key"] = _options.ApiKey,
["distinct_id"] = _options.DistinctId,
["event"] = eventName,
["properties"] = properties ?? new Dictionary<string, object>()
};
json = ser.Serialize(payload, 0);
}
var url = $"{_options.BaseUrl.TrimEnd('/')}/i/v0/e";
try
{
using (var response = await _httpClient.PostAsync(
url,
new StringContent(json, Encoding.UTF8, "application/json"),
cancellationToken
))
{
response.EnsureSuccessStatusCode();
}
}
catch (Exception ex)
{
// Log and swallow for fire-and-forget telemetry
_logger?.Error($"Failed to send telemetry event '{eventName}': {ex.Message}");
}
}
public void Dispose()
{
if (_disposed) return;
_disposed = true;
_httpClient.Dispose();
}
}
}