Permalink
Browse files

asynchronous APIs - lots of changes, completely untested

  • Loading branch information...
1 parent 665cba2 commit 697467ad0c696c44836de51d55e9a63e8ee2d604 @jkowalski committed May 9, 2010
Showing with 2,025 additions and 332 deletions.
  1. +36 −4 src/LocalTestRun.netfx40.testrunconfig
  2. +1 −0 src/NLog.proj
  3. +12 −11 src/NLog/Config/LoggingConfiguration.cs
  4. +39 −0 src/NLog/Internal/AsyncContinuation.cs
  5. +255 −0 src/NLog/Internal/AsyncHelpers.cs
  6. +39 −0 src/NLog/Internal/AsynchronousAction.cs
  7. +46 −0 src/NLog/Internal/ExtensionAttribute.cs
  8. +70 −0 src/NLog/Internal/SingleCallContinuation.cs
  9. +37 −0 src/NLog/Internal/SynchronousAction.cs
  10. +90 −0 src/NLog/Internal/TimeoutContinuation.cs
  11. +38 −3 src/NLog/LogFactory.cs
  12. +56 −24 src/NLog/LogManager.cs
  13. +106 −65 src/NLog/LoggerImpl.cs
  14. +9 −1 src/NLog/NLog.mono2.csproj
  15. +9 −1 src/NLog/NLog.netcf20.csproj
  16. +10 −1 src/NLog/NLog.netcf35.csproj
  17. +9 −1 src/NLog/NLog.netfx20.csproj
  18. +9 −1 src/NLog/NLog.netfx35.csproj
  19. +9 −1 src/NLog/NLog.netfx40.csproj
  20. +9 −1 src/NLog/NLog.sl2.csproj
  21. +9 −1 src/NLog/NLog.sl3.csproj
  22. +9 −1 src/NLog/NLog.sl4.csproj
  23. +2 −2 src/NLog/{Config → }/NLogConfigurationException.cs
  24. +90 −0 src/NLog/NLogRuntimeException.cs
  25. +1 −1 src/NLog/ProjectFileInfo.xml
  26. +12 −1 src/NLog/Targets/Compound/CompoundTargetBase.cs
  27. +48 −15 src/NLog/Targets/Compound/FallbackTarget.cs
  28. +13 −5 src/NLog/Targets/Compound/RandomizeTarget.cs
  29. +7 −4 src/NLog/Targets/Compound/RoundRobinTarget.cs
  30. +7 −5 src/NLog/Targets/Compound/SplitTarget.cs
  31. +15 −6 src/NLog/Targets/FileTarget.cs
  32. +9 −4 src/NLog/Targets/NetworkTarget.cs
  33. +88 −31 src/NLog/Targets/Target.cs
  34. +1 −2 src/NLog/Targets/Wrappers/AspNetBufferingTargetWrapper.cs
  35. +1 −1 src/NLog/Targets/Wrappers/AsyncRequestQueue-T.cs
  36. +49 −58 src/NLog/Targets/Wrappers/AsyncTargetWrapper.cs
  37. +7 −4 src/NLog/Targets/Wrappers/AutoFlushTargetWrapper.cs
  38. +24 −12 src/NLog/Targets/Wrappers/BufferingTargetWrapper.cs
  39. +9 −2 src/NLog/Targets/Wrappers/FilteringTargetWrapper.cs
  40. +6 −4 src/NLog/Targets/Wrappers/ImpersonatingTargetWrapper.cs
  41. +14 −5 src/NLog/Targets/Wrappers/PostFilteringTargetWrapper.cs
  42. +6 −25 src/NLog/Targets/Wrappers/RepeatingTargetWrapper.cs
  43. +26 −17 src/NLog/Targets/Wrappers/RetryingTargetWrapper.cs
  44. +15 −3 src/NLog/Targets/Wrappers/WrapperTargetBase.cs
  45. +427 −0 tests/NLog.UnitTests/AsyncHelperTests.cs
  46. +2 −0 tests/NLog.UnitTests/NLog.UnitTests.netcf20.csproj
  47. +2 −0 tests/NLog.UnitTests/NLog.UnitTests.netcf35.csproj
  48. +2 −0 tests/NLog.UnitTests/NLog.UnitTests.netfx20.csproj
  49. +2 −0 tests/NLog.UnitTests/NLog.UnitTests.netfx35.csproj
  50. +2 −0 tests/NLog.UnitTests/NLog.UnitTests.netfx40.csproj
  51. +2 −0 tests/NLog.UnitTests/NLog.UnitTests.sl2.csproj
  52. +2 −0 tests/NLog.UnitTests/NLog.UnitTests.sl3.csproj
  53. +2 −0 tests/NLog.UnitTests/NLog.UnitTests.sl4.csproj
  54. +1 −1 tests/NLog.UnitTests/ProjectFileInfo.xml
  55. +5 −0 tests/NLog.UnitTests/SourceCodeTests.cs
  56. +10 −7 tests/NLog.UnitTests/Targets/ConcurrentFileTargetTests.cs
  57. +4 −1 tests/NLog.UnitTests/Targets/FileTargetTests.cs
  58. +205 −0 tests/NLog.UnitTests/Targets/Wrappers/AutoFlushTargetWrapperTests.cs
@@ -1,5 +1,37 @@
-<?xml version="1.0" encoding="utf-8"?>
-<TestRunConfiguration name="Local Test Run" id="d5ad33a1-e178-4da8-880b-e73a8eedbdbe" xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
+<?xml version="1.0" encoding="UTF-8"?>
+<TestSettings name="Local Test Run" id="d5ad33a1-e178-4da8-880b-e73a8eedbdbe" xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
<Description>This is a default test run configuration for a local test run.</Description>
- <TestTypeSpecific />
-</TestRunConfiguration>
+ <Execution>
+ <TestTypeSpecific>
+ <UnitTestRunConfig testTypeId="13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b">
+ <AssemblyResolution>
+ <TestDirectory useLoadContext="true" />
+ </AssemblyResolution>
+ </UnitTestRunConfig>
+ <WebTestRunConfiguration testTypeId="4e7599fa-5ecb-43e9-a887-cd63cf72d207">
+ <Browser name="Internet Explorer 7.0">
+ <Headers>
+ <Header name="User-Agent" value="Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)" />
+ <Header name="Accept" value="*/*" />
+ <Header name="Accept-Language" value="{{$IEAcceptLanguage}}" />
+ <Header name="Accept-Encoding" value="GZIP" />
+ </Headers>
+ </Browser>
+ </WebTestRunConfiguration>
+ </TestTypeSpecific>
+ <AgentRule name="LocalMachineDefaultRole">
+ <DataCollectors>
+ <DataCollector uri="datacollector://Microsoft/CodeCoverage/1.0" assemblyQualifiedName="Microsoft.VisualStudio.TestTools.CodeCoverage.CoveragePlugIn, Microsoft.VisualStudio.QualityTools.Plugins.CodeCoverage, PublicKeyToken=b03f5f7f11d50a3a" friendlyName="Code Coverage">
+ <Configuration>
+ <CodeCoverage keyFile="NLog.snk" xmlns="">
+ <Regular>
+ <CodeCoverageItem binaryFile="NLog\bin\Debug\.NET Framework 4.0\NLog.dll" pdbFile="NLog\bin\Debug\.NET Framework 4.0\NLog.pdb" instrumentInPlace="true" />
+ <CodeCoverageItem binaryFile="NLog\bin\Debug\.NET Framework 4.0\NLog.Extended.dll" pdbFile="NLog\bin\Debug\.NET Framework 4.0\NLog.Extended.pdb" instrumentInPlace="true" />
+ </Regular>
+ </CodeCoverage>
+ </Configuration>
+ </DataCollector>
+ </DataCollectors>
+ </AgentRule>
+ </Execution>
+</TestSettings>
View
@@ -248,6 +248,7 @@
</Target>
<Target Name="CheckinSuite">
+ <CallTarget Targets="SyncProjectItems" />
<CallTarget Targets="DeepClean" />
<CallTarget Targets="Rebuild" />
<CallTarget Targets="DumpApi" />
@@ -40,6 +40,7 @@ namespace NLog.Config
using NLog.Common;
using NLog.Internal;
using NLog.Targets;
+ using System.Threading;
/// <summary>
/// Keeps logging configuration and provides simple API
@@ -193,22 +194,22 @@ internal void Dump()
/// <summary>
/// Flushes any pending log messages on all appenders.
/// </summary>
- /// <param name="timeout">
- /// The timeout.
- /// </param>
- internal void FlushAllTargets(TimeSpan timeout)
+ /// <param name="asyncContinuation">The asynchronous continuation.</param>
+ internal void FlushAllTargets(AsyncContinuation asyncContinuation)
{
- foreach (Target target in this.targets.Values)
+ List<Target> targets = new List<Target>();
+ foreach (var rule in this.LoggingRules)
{
- try
- {
- target.Flush(timeout);
- }
- catch (Exception ex)
+ foreach (var t in rule.Targets)
{
- InternalLogger.Error("Error while flushing target: {0} {1}", target.Name, ex);
+ if (!targets.Contains(t))
+ {
+ targets.Add(t);
+ }
}
}
+
+ AsyncHelpers.RunInParallel(targets, asyncContinuation, (cont, target) => target.Flush(cont));
}
internal void InitializeAll()
@@ -0,0 +1,39 @@
+//
+// Copyright (c) 2004-2010 Jaroslaw Kowalski <jaak@jkowalski.net>
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * Neither the name of Jaroslaw Kowalski nor the names of its
+// contributors may be used to endorse or promote products derived from this
+// software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+namespace NLog.Internal
+{
+ using System;
+
+ public delegate void AsyncContinuation(Exception exception);
+}
@@ -0,0 +1,255 @@
+//
+// Copyright (c) 2004-2010 Jaroslaw Kowalski <jaak@jkowalski.net>
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * Neither the name of Jaroslaw Kowalski nor the names of its
+// contributors may be used to endorse or promote products derived from this
+// software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+namespace NLog.Internal
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Threading;
+ using NLog.Common;
+
+ /// <summary>
+ /// Helpers for asynchronous operations.
+ /// </summary>
+ public static class AsyncHelpers
+ {
+ public static void LogException(Exception ex)
+ {
+ InternalLogger.Error("EXCEPTION: {0}", ex);
+ }
+
+ public static void ForEachItemSequentially<T>(IEnumerable<T> items, AsyncContinuation asyncContinuation, AsynchronousAction<T> action)
+ {
+ action = ExceptionGuard(action);
+ AsyncContinuation invokeNext = null;
+ IEnumerator<T> enumerator = items.GetEnumerator();
+
+ invokeNext = ex =>
+ {
+ if (ex != null)
+ {
+ asyncContinuation(ex);
+ return;
+ }
+
+ if (!enumerator.MoveNext())
+ {
+ asyncContinuation(null);
+ return;
+ }
+
+ action(invokeNext.OneTimeOnly(), enumerator.Current);
+ };
+
+ invokeNext(null);
+ }
+
+ public static void Repeat(int repeatCount, AsyncContinuation asyncContinuation, AsynchronousAction action)
+ {
+ action = ExceptionGuard(action);
+ AsyncContinuation invokeNext = null;
+ int remaining = repeatCount;
+
+ invokeNext = ex =>
+ {
+ if (ex != null)
+ {
+ asyncContinuation(ex);
+ return;
+ }
+
+ if (remaining-- <= 0)
+ {
+ asyncContinuation(null);
+ return;
+ }
+
+ action(invokeNext.OneTimeOnly());
+ };
+
+ invokeNext(null);
+ }
+
+ private static AsynchronousAction ExceptionGuard(AsynchronousAction action)
+ {
+ return cont =>
+ {
+ try
+ {
+ action(cont);
+ }
+ catch (Exception ex)
+ {
+ cont(ex);
+ }
+ };
+ }
+
+ private static AsynchronousAction<T> ExceptionGuard<T>(AsynchronousAction<T> action)
+ {
+ return (AsyncContinuation cont, T argument) =>
+ {
+ try
+ {
+ action(cont, argument);
+ }
+ catch (Exception ex)
+ {
+ cont(ex);
+ }
+ };
+ }
+
+ /// <summary>
+ /// Modifies the continuation by pre-pending given action to execute just before it.
+ /// </summary>
+ /// <param name="asyncContinuation">The async continuation.</param>
+ /// <param name="action">The action to pre-pend.</param>
+ /// <returns>Continuation which will execute the given action before forwarding to the actual continuation.</returns>
+ public static AsyncContinuation PrecededBy(this AsyncContinuation asyncContinuation, AsynchronousAction action)
+ {
+ action = ExceptionGuard(action);
+
+ AsyncContinuation continuation =
+ ex =>
+ {
+ if (ex != null)
+ {
+ // if got exception from from original invocation, don't execute action
+ asyncContinuation(ex);
+ return;
+ }
+
+ // call the action and continue
+ action(asyncContinuation.OneTimeOnly());
+ };
+
+ return continuation;
+ }
+
+ public static AsyncContinuation PrecededByRegardlessOfResult(this AsyncContinuation asyncContinuation, SynchronousAction action)
+ {
+ throw new NotImplementedException();
+ }
+
+ public static AsyncContinuation WithTimeout(this AsyncContinuation asyncContinuation, TimeSpan timeout)
+ {
+ return new TimeoutContinuation(asyncContinuation, timeout).Function;
+ }
+
+ public static void RunInParallel<T>(IEnumerable<T> values, AsyncContinuation asyncContinuation, AsynchronousAction<T> action)
+ {
+ action = ExceptionGuard(action);
+
+ var items = new List<T>(values);
+ int remaining = items.Count;
+ var exceptions = new List<Exception>();
+
+ InternalLogger.Trace("RunInParallel() {0} items", items.Count);
+
+ if (remaining == 0)
+ {
+ asyncContinuation(null);
+ return;
+ }
+
+ AsyncContinuation continuation =
+ ex =>
+ {
+ int r;
+
+ if (ex == null)
+ {
+ r = Interlocked.Decrement(ref remaining);
+ InternalLogger.Trace("Parallel task completed. {0} items remaining", r);
+ if (r == 0)
+ {
+ if (exceptions.Count == 0)
+ {
+ asyncContinuation(null);
+ }
+ else
+ {
+ asyncContinuation(new NLogRuntimeException("TODO - combine all exceptions into one."));
+ }
+ }
+
+ return;
+ }
+
+ lock (exceptions)
+ {
+ exceptions.Add(ex);
+ }
+
+ r = Interlocked.Decrement(ref remaining);
+ InternalLogger.Trace("Parallel task failed {0}. {1} items remaining", ex, r);
+ if (r == 0)
+ {
+ asyncContinuation(new NLogRuntimeException("TODO - combine all exceptions into one."));
+ }
+ };
+
+ foreach (var v in items)
+ {
+ action(OneTimeOnly(continuation), v);
+ }
+ }
+
+ public static void RunSynchronously(AsynchronousAction action)
+ {
+ var ev = new ManualResetEvent(false);
+ Exception lastException = null;
+
+ action(OneTimeOnly(ex => { lastException = ex; ev.Set(); }));
+ ev.WaitOne();
+ if (lastException != null)
+ {
+ throw new NLogRuntimeException("Asynchronous exception has occured.");
+ }
+ }
+
+ public static AsyncContinuation OneTimeOnly(this AsyncContinuation asyncContinuation)
+ {
+#if !NETCF2_0
+ // target is not available on .NET CF 2.0
+ if (asyncContinuation.Target is SingleCallContinuation)
+ {
+ return asyncContinuation;
+ }
+#endif
+
+ return new SingleCallContinuation(asyncContinuation).Function;
+ }
+ }
+}
Oops, something went wrong.

0 comments on commit 697467a

Please sign in to comment.