Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactored the library #21

Merged
merged 12 commits into from Jan 29, 2019
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<log4net>
<root>
<level value="ALL" />
<appender-ref ref="LogglyAppender" />
</root>
<appender name="LogglyAppender" type="log4net.loggly.LogglyAppender, log4net-loggly">
<rootUrl value="https://fake.logs-01.loggly.com/" />
<inputKey value="customer-token" />
</appender>
</log4net>
</configuration>
@@ -0,0 +1,81 @@
using System;

namespace log4net_loggly_stress_tool
{
internal class CommandLineArgs
{
public int NumEvents { get; private set; } = 1000;
public int NumLoggingThreads { get; private set; } = 1;
public int ExceptionFrequency { get; private set; } = 0;
public TimeSpan SendDelay { get; private set; } = TimeSpan.Zero;

public static CommandLineArgs Parse(string[] args)
{
var result = new CommandLineArgs();

try
{
for (int i = 0; i < args.Length; i++)
{
switch (args[i])
{
case "-n":
case "--num-events":
i++;
result.NumEvents = int.Parse(args[i]);
if (result.NumEvents < 1)
throw new ArgumentException("Number of events must be >= 1");
break;
case "-t":
case "--num-threads":
i++;
result.NumLoggingThreads = int.Parse(args[i]);
if (result.NumLoggingThreads < 1)
throw new ArgumentException("Number of threads must be >= 1");
break;
case "-d":
case "--send-delay":
i++;
var value = int.Parse(args[i]);
if (value < 0)
throw new ArgumentException("Delay must be >= 0");
result.SendDelay = TimeSpan.FromMilliseconds(value);
break;
case "-e":
case "--exception-every":
i++;
result.ExceptionFrequency = int.Parse(args[i]);
if (result.ExceptionFrequency < 0)
throw new ArgumentException("Exception frequency must be >= 0");
break;
default:
PrintHelp();
break;
}
}
}
catch (Exception e)
{
PrintHelp();
}

return result;
}

private static void PrintHelp()
{
Console.WriteLine(@"
Loggly log4net logger stress testing tool.
Tool is generating log messages in one or more threads and logs them to logger.
Fake HTTP layer is used to fake sending data to Loggly, no data are really sent out.
Usage: log4net-loggly-stress-tool.exe [-n|--num-threads <NUM_THREADS>] [-d|--send-delay <SEND_DELAY_MS>] [-e|--exception-every <NUMBER>]
-n|--num-events - Number of events to send. Must be > 0. Default: 1000
-t|--num-threads - Number of threads used to generate logs. Must be > 0. Default: 1.
-d|--send-delay - Delay for one simulated send to Loggly servers in milliseconds. Must be >= 0. Default: 0
-e|--exception-every - Log error with exception every N logs. Must be >= 0. Default: 0 - never");

Environment.Exit(0);
}
}
}
@@ -0,0 +1,125 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using log4net;
using log4net.loggly;

namespace log4net_loggly_stress_tool
{
public class Program
{
private static ILog _log;

private static long _count = 0;

public static void Main(string[] args)
{
var commandLine = CommandLineArgs.Parse(args);

var client = new TestHttpClient(commandLine.SendDelay);
// use test HTTP layer
LogglyClient.HttpClient = client;

var logRepository = LogManager.GetRepository(Assembly.GetEntryAssembly());
log4net.Config.XmlConfigurator.Configure(logRepository);

_log = LogManager.GetLogger(typeof(Program));

SetupThreadContext();

var exception = GetTestException();

Console.WriteLine("Running test in {0} threads with {1} ms delay for send and exception every {2} messages.",
commandLine.NumLoggingThreads, commandLine.SendDelay, commandLine.ExceptionFrequency);

var watch = Stopwatch.StartNew();
var tasks = new List<Task>(commandLine.NumLoggingThreads);
for (int i = 0; i < commandLine.NumLoggingThreads; i++)
{
tasks.Add(Task.Factory.StartNew(() => SendContinuously(commandLine, exception), TaskCreationOptions.LongRunning));
}

Task.WaitAll(tasks.ToArray());

watch.Stop();

Console.WriteLine("Test finished. Elasped: {0}", watch.Elapsed);
}

private static void SendContinuously(CommandLineArgs commandLine, Exception exception)
{
long currentCount = 0;
while ((currentCount = Interlocked.Increment(ref _count)) <= commandLine.NumEvents)
{
if (currentCount % 1000 == 0)
{
Console.WriteLine("Sent: {0}", currentCount);
}

if (commandLine.ExceptionFrequency > 0 && currentCount % commandLine.ExceptionFrequency == 0)
{
_log.Error(
$"Test message {currentCount} Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus fermentum ligula " +
"et ante tincidunt venenatis. Ut pretium, mi laoreet fringilla egestas, mauris quam lacinia dolor, " +
"eu maximus nisi mauris vel lorem. Duis a ex eu orci consectetur congue sed sit amet ligula. " +
"Aenean congue mollis quam volutpat varius.", exception);
}
else
{
_log.Info(
$"Test message {currentCount}. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus fermentum ligula " +
"et ante tincidunt venenatis. Ut pretium, mi laoreet fringilla egestas, mauris quam lacinia dolor, " +
"eu maximus nisi mauris vel lorem. Duis a ex eu orci consectetur congue sed sit amet ligula. " +
"Aenean congue mollis quam volutpat varius.");
}
}
}


private static Exception GetTestException()
{
Exception exception;
try
{
try
{
throw new ArgumentException("inner exception");
}
catch (Exception e)
{
throw new InvalidOperationException("outer exception", e);
}
}
catch (Exception e)
{
exception = e;
}

return exception;
}

private static void SetupThreadContext()
{
ThreadContext.Properties["ThreadProperty1"] = DateTime.Now;
ThreadContext.Properties["ThreadProperty2"] = new TestClass
{
IntProperty = 123,
StringProperty =
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus fermentum ligula et ante tincidunt venenatis. " +
"Ut pretium, mi laoreet fringilla egestas, mauris quam lacinia dolor, eu maximus nisi mauris vel lorem. " +
"Duis a ex eu orci consectetur congue sed sit amet ligula. Aenean congue mollis quam volutpat varius.",
DatetimeProperty = DateTime.Now
};
}

private class TestClass
{
public int IntProperty { get; set; }
public string StringProperty { get; set; }
public DateTime DatetimeProperty { get; set; }
}
}
}
@@ -0,0 +1,21 @@
using System;
using System.Threading;
using log4net.loggly;

namespace log4net_loggly_stress_tool
{
internal class TestHttpClient : ILogglyHttpClient
{
private readonly TimeSpan _sendDelay;

public TestHttpClient(TimeSpan sendDelay)
{
_sendDelay = sendDelay;
}

public void Send(ILogglyAppenderConfig config, string tag, string message)
{
Thread.Sleep(_sendDelay);
}
}
}
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net45</TargetFramework>
<RootNamespace>log4net_loggly_stress_tool</RootNamespace>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="log4net" Version="2.0.8" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\log4net-loggly\log4net-loggly.csproj" />
</ItemGroup>

</Project>
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<log4net>
<root>
<level value="ALL" />
<appender-ref ref="LogglyAppender" />
</root>
<appender name="LogglyAppender" type="log4net.loggly.LogglyAppender, log4net-loggly">
<rootUrl value="https://fake.logs-01.loggly.com/" />
<inputKey value="your-customer-token" />
<tag value="your-custom-tag" />
<logicalThreadContextKeys value="lkey1,lkey2,CommonProperty" />
<!-- optional -->
<globalContextKeys value="gkey1,gkey2,CommonProperty" />
<!-- optional -->
</appender>
</log4net>
</configuration>
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.