@@ -14,11 +14,16 @@ namespace Datadog.Trace
         private readonly AgentWriterBuffer<ServiceInfo> _servicesBuffer = new AgentWriterBuffer<ServiceInfo>(100);
         private readonly IApi _api;
         private readonly Task _flushTask;
+        private readonly TaskCompletionSource<bool> _processExit = new TaskCompletionSource<bool>();
 
         public AgentWriter(IApi api)
         {
             _api = api;
             _flushTask = Task.Run(FlushTracesTaskLoop);
+            // Register callbacks to make sure we flush the traces before exiting
+            AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit;
+            AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
+            Console.CancelKeyPress += Console_CancelKeyPress;
         }
 
         public void WriteServiceInfo(ServiceInfo serviceInfo)
﻿using Datadog.Trace.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Datadog.Trace
{
    internal class AgentWriter : IAgentWriter
    {
        private static ILog _log = LogProvider.For<AgentWriter>();

        private readonly AgentWriterBuffer<List<Span>> _tracesBuffer = new AgentWriterBuffer<List<Span>>(1000);
        private readonly AgentWriterBuffer<ServiceInfo> _servicesBuffer = new AgentWriterBuffer<ServiceInfo>(100);
        private readonly IApi _api;
        private readonly Task _flushTask;

        public AgentWriter(IApi api)
        {
            _api = api;
            _flushTask = Task.Run(FlushTracesTaskLoop);
        }

        public void WriteServiceInfo(ServiceInfo serviceInfo)
        {
            var success = _servicesBuffer.Push(serviceInfo);
            if (!success)
            {
                _log.Debug("ServiceInfo buffer is full, dropping it.");
            }
        }

        public void WriteTrace(List<Span> trace)
        {
            var success = _tracesBuffer.Push(trace);
            if (!success)
            {
                _log.Debug("Trace buffer is full, dropping it.");
            }
        }

        public async Task FlushTracesTaskLoop()
        {
            while (true)
            {
                try
                {
                    // TODO:bertrand trigger on process exit too
                    await Task.Delay(TimeSpan.FromSeconds(1));
                    var traces = _tracesBuffer.Pop();
                    if (traces.Any())
                    {
                        await _api.SendTracesAsync(traces);
                    }
                    var services = _servicesBuffer.Pop();
                    if (services.Any())
                    {
                        // TODO:bertrand batch these calls
                        await Task.WhenAll(services.Select(_api.SendServiceAsync));
                    }
                }
                catch(Exception ex)
                {
                    _log.ErrorException("An unhandled error occurred during the flushing task", ex);
                }
            }
        }
    }
}

can't we have this at the Tracer level? my point about having the logic of "Write" in the Tracer, is that this `AgentWriter` is a class that may have multiple implementations, so this logic will be replicated. Think about the possibility of having a `SyncWriter` that writes immediately in the main thread (it was a specific use case that came out in the Ruby client)