snowplow-dotnet-tracker icon indicating copy to clipboard operation
snowplow-dotnet-tracker copied to clipboard

An item with the same key has already been added. Key: stm

Open jahanbinali1988 opened this issue 8 months ago • 1 comments

Describe the bug I am using the "snowplow.tracker" Nuget package in my dotnet core project. when I deployed my code on the server with the container, my server restarted every 2 minutes with the following error.

Occurred exception Unhandled exception. System.ArgumentException: An item with the same key has already been added. Key: stm at System.Collections.Generic.Dictionary2.TryInsert(TKey key, TValue value, InsertionBehavior behavior) at System.Collections.Generic.Dictionary2.Add(TKey key, TValue value) at Snowplow.Tracker.Endpoints.SnowplowHttpCollectorEndpoint.AddSendTimestamp(List1 payloadList) at Snowplow.Tracker.Endpoints.SnowplowHttpCollectorEndpoint.SendPostAsync(List1 itemList) at Snowplow.Tracker.Endpoints.SnowplowHttpCollectorEndpoint.Send(List`1 itemList) at Snowplow.Tracker.Emitters.AsyncEmitter.loop()

Additional context

public class SnowplowService : ISnowplowService { private readonly SnowplowConfig _configuration; private readonly ILogger<SnowplowService> _logger;

public SnowplowService(IOptions<SnowplowConfig> configuration,
    ILogger<SnowplowService> logger)
{
    this._configuration = configuration.Value;
    this._logger = logger;
}

public async Task<SnowplowResponse> SendEvent(SnowplowRequest request)
{
    var response = new SnowplowResponse();
    var tracker = Tracker.Instance;            
    var logger = new ConsoleLogger();
    var endpoint = new SnowplowHttpCollectorEndpoint
        (host: _configuration.BaseAddress, port: _configuration.Port, l: logger,
        method: Snowplow.Tracker.Endpoints.HttpMethod.POST, protocol: HttpProtocol.HTTP);

    try
    {
        var queue = new InMemoryBlockingQueue();
        var emitter = new AsyncEmitter(endpoint, queue, l: logger);
        var subject = new Subject().SetPlatform(Platform.Srv).SetLang(_configuration.Language);

        if (tracker.Started == false)
        {
            tracker.Start(
                emitter: emitter,
                subject: subject,
                trackerNamespace: _configuration.TrackerNamespace,
                appId: _configuration.AppId,
                encodeBase64: false,
                l: logger);
        }

        if (tracker.Started)
        {
            var dataKeyValues = new Dictionary<string, object>
            {
                { "userId", request.UserId! },
                { "eventName", request.EventName },
                { "eventTime", request.EventTime },
                { "eventData", Utility.ConvertToDictionaryObject(request: request.EventData) }
            };
            
            var eventKeyValues = new Dictionary<string, object>()
            {
                { "vendor", _configuration.Vendor! },
                { "model", request.SnowplowRequestName!},
            };

            var eventData = new SelfDescribingJson
                ($"iglu:{_configuration.Vendor}/{request.SnowplowRequestName!}/jsonschema/1-0-0", dataKeyValues);

            var requestItem = new List<IContext>();

            var context = new GenericContext()
                .SetSchema($"iglu:com.vendor/meta/jsonschema/1-0-0")
                .AddDict(eventKeyValues)
                .Build();

            requestItem.Add(item: context);

            var trackingItem =
                new SelfDescribing()
                .SetEventData(eventData: eventData)
                .SetCustomContext(customContexts: requestItem)
                .Build();
            
            tracker.Track(newEvent: trackingItem);
        }

        response = new SnowplowResponse(true, "");
    }
    catch (Exception ex)
    {
        response = new SnowplowResponse(false, ex.Message);
    }

    return response;
}

}

	internal static Dictionary<string, object> ConvertToDictionaryObject<T>(T request) where T : class
	{
		var result = new Dictionary<string, object>();

		var properties = request.GetType().GetProperties();

		foreach (var item in properties)
		{
			var key = item.Name.ToLower().Trim();

			var value = item.GetValue(request);

			if (result.ContainsKey(key) == false)
				result.Add(key: key, value: value!);
		}

		return result;
	}

jahanbinali1988 avatar Nov 08 '23 14:11 jahanbinali1988