I have some ideas for developing a new AsyncAppenderSkeleton, based on recent experience developing a custom async appender that sends logging events to a Web API.
My current thoughts are: 1. A new base class AsyncAppenderSkeleton that can be configured to work in synchronous mode (identical to AppenderSkeleton) or asynchronous mode, where DoAppend queues events on to a FIFO queue, and has a single background thread that dequeues events and calls the existing Append methods. 2. When in asynchronous mode, there will be customizable and configurable retry logic that can call Append if it throws an exception. The retry login will be able to inspect the exception that was thrown and keep a count of the number of retries so far. For example, a derived appender that logs to a Web API might want to retry 5xx HTTP status codes, but treat 4xx status codes as permanent errors. There will no retry logic in synchronous mode as this would impact performance. 3. The default queue implementation would be a lossy in-memory Queue with a configurable maximum length. It might be nice to provide the possibility to plug in alternate queue implementations, such as a persistent queue using MSMQ. 4. A class AsyncForwardingAppender would derive from AsyncAppenderSkeleton and implement IAppenderAttachable. 5. It would be easy to create asynchronous versions of existing custom appenders, by changing the base class from AppenderSkeleton to AsyncAppenderSkeleton and optionally implementing some retry logic. E.g. we could have a new AdoNetAppender that can be configured to operate in synchronous mode when logging to a local database, or in asynchronous mode when logging to a cloud-based database. In terms of timescales, I think it would be possible to produce something by the end of 2016. To do it I need to reimplement AppenderSkeleton's DoAppend methods, to enqueue events if in asynchronous mode, or call Append in synchronous mode. I don't want to duplicate code by reimplementing the rest of AppenderSkeleton, so I would like to do one of the following: Option 1: - Refactor all of AppenderSkeleton's implementation except IAppender and IBulkAppender into a new base class AppenderSkeletonBase. This includes filtering, IOptionHandler, layout. - Derive AppenderSkeleton and later the new AsyncAppenderSkeleton from AppenderSkeletonBase. Option 2: - Make AppenderSkeleton's DoAppend methods virtual, and derive AsyncAppenderSkeleton from AppenderSkeleton. Option 1 seems the cleanest to me; any thoughts?