public Logger(params AbstractWriter[] writers) { Contract.Requires(writers != null); Contract.Requires(writers.Length >= 1); cts = new CancellationTokenSource(); bufferBlocks = new List <BufferBlock <LogItem> >(); writerBlocks = new List <ActionBlock <LogItem[]> >(); foreach (var writer in writers) { writer.Setup(); var bufferBlock = new BufferBlock <LogItem>( new DataflowBlockOptions() { CancellationToken = cts.Token }); var batchBlock = new BatchBlock <LogItem>( writer.BatchSize, new GroupingDataflowBlockOptions() { Greedy = true, CancellationToken = cts.Token }); var timer = new Timer(state => batchBlock.TriggerBatch()); var timeoutBlock = new TransformBlock <LogItem, LogItem>( value => { timer.Change((int)writer.Timeout.TotalMilliseconds, Timeout.Infinite); return(value); }, new ExecutionDataflowBlockOptions() { CancellationToken = cts.Token, SingleProducerConstrained = true }); var writerBlock = new ActionBlock <LogItem[]>( async logItems => { await writer.WriteAsync(logItems); }, new ExecutionDataflowBlockOptions() { MaxDegreeOfParallelism = 1, CancellationToken = cts.Token, SingleProducerConstrained = true }); writerBlock.Completion.ContinueWith(task => writer.Teardown()); timeoutBlock.LinkTo(batchBlock); bufferBlock.LinkTo(timeoutBlock); batchBlock.LinkTo(writerBlock); writerBlocks.Add(writerBlock); bufferBlocks.Add(bufferBlock); timeoutBlock.HandleCompletion(batchBlock); bufferBlock.HandleCompletion(timeoutBlock); batchBlock.HandleCompletion(writerBlock); } }