Skip to content

Commit 0b2b681

Browse files
Merge pull request #22 from psquickitjayant/develop
Added support for bulk mode
2 parents e472728 + b4dd17f commit 0b2b681

File tree

8 files changed

+182
-59
lines changed

8 files changed

+182
-59
lines changed

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ You can also use **layout** with in the Config to render logs according to your
4141
<conversionPattern value="%date [%thread] %-5level %logger %message" />
4242
</layout>
4343

44+
By default, library uses Loggly /bulk end point (https://www.loggly.com/docs/http-bulk-endpoint/). To use /inputs endpoint, add the following configuration in config file.
45+
46+
```
47+
<logMode value="inputs" />
48+
```
49+
50+
4451
Add the following entry in your AssemblyInfo.cs
4552
```
4653
[assembly: log4net.Config.XmlConfigurator(Watch = true)]

source/log4net-loggly/ILogglyAppenderConfig.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ public interface ILogglyAppenderConfig
55
string RootUrl { get; set; }
66
string InputKey { get; set; }
77
string UserAgent { get; set; }
8+
string LogMode { get; set; }
89
int TimeoutInSeconds { get; set; }
9-
string Tag { get; set; }
10-
string LogicalThreadContextKeys { get; set; }
11-
string GlobalContextKeys { get; set; }
12-
}
10+
string Tag { get; set; }
11+
string LogicalThreadContextKeys { get; set; }
12+
string GlobalContextKeys { get; set; }
13+
}
1314
}
Lines changed: 83 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,102 @@
11
using log4net.Appender;
22
using log4net.Core;
3-
using System.Threading;
4-
using System.Threading.Tasks;
3+
using System;
54
using System.Collections.Generic;
5+
using Timer = System.Timers;
6+
67

78

89
namespace log4net.loggly
910
{
1011
public class LogglyAppender : AppenderSkeleton
1112
{
13+
List<string> lstLogs = new List<string>();
14+
string[] arr = new string[100];
1215
public static readonly string InputKeyProperty = "LogglyInputKey";
13-
1416
public static ILogglyFormatter Formatter = new LogglyFormatter();
1517
public static ILogglyClient Client = new LogglyClient();
16-
1718
private ILogglyAppenderConfig Config = new LogglyAppenderConfig();
18-
1919
public string RootUrl { set { Config.RootUrl = value; } }
2020
public string InputKey { set { Config.InputKey = value; } }
2121
public string UserAgent { set { Config.UserAgent = value; } }
22+
public string LogMode { set { Config.LogMode = value; } }
2223
public int TimeoutInSeconds { set { Config.TimeoutInSeconds = value; } }
23-
public string Tag { set { Config.Tag = value; } }
24-
public string LogicalThreadContextKeys { set { Config.LogicalThreadContextKeys = value; } }
25-
public string GlobalContextKeys { set { Config.GlobalContextKeys = value; } }
26-
27-
protected override void Append(LoggingEvent loggingEvent)
28-
{
29-
SendLogAction(loggingEvent);
30-
}
31-
32-
private void SendLogAction(LoggingEvent loggingEvent)
33-
{
34-
//we should always format event in the same thread as
35-
//many properties used in the event are associated with the current thread
36-
//like threadname, ndc stacks, threadcontent properties etc.
37-
38-
//initializing a string for the formatted log
39-
string _formattedLog = string.Empty;
40-
41-
//if Layout is null then format the log from the Loggly Client
42-
if (this.Layout == null)
43-
{
44-
Formatter.AppendAdditionalLoggingInformation(Config, loggingEvent);
45-
_formattedLog = Formatter.ToJson(loggingEvent);
46-
}
47-
else
48-
{
49-
_formattedLog = Formatter.ToJson(RenderLoggingEvent(loggingEvent), loggingEvent.TimeStamp);
50-
}
51-
52-
//sending _formattedLog to the async queue
53-
ThreadPool.QueueUserWorkItem(x => Client.Send(Config, _formattedLog));
54-
}
24+
public string Tag { set { Config.Tag = value; } }
25+
public string LogicalThreadContextKeys { set { Config.LogicalThreadContextKeys = value; } }
26+
public string GlobalContextKeys { set { Config.GlobalContextKeys = value; } }
27+
28+
private LogglyAsyncHandler LogglyAsync;
29+
30+
public LogglyAppender()
31+
{
32+
LogglyAsync = new LogglyAsyncHandler();
33+
Timer.Timer t = new Timer.Timer();
34+
t.Interval = 20000;
35+
t.Enabled = true;
36+
t.Elapsed += t_Elapsed;
37+
}
38+
39+
void t_Elapsed(object sender, Timer.ElapsedEventArgs e)
40+
{
41+
if (lstLogs.Count != 0)
42+
{
43+
SendAllEvents(lstLogs.ToArray());
44+
}
45+
}
46+
47+
protected override void Append(LoggingEvent loggingEvent)
48+
{
49+
SendLogAction(loggingEvent);
50+
}
51+
52+
private void SendLogAction(LoggingEvent loggingEvent)
53+
{
54+
//we should always format event in the same thread as
55+
//many properties used in the event are associated with the current thread
56+
//like threadname, ndc stacks, threadcontent properties etc.
57+
58+
//initializing a string for the formatted log
59+
string _formattedLog = string.Empty;
60+
61+
//if Layout is null then format the log from the Loggly Client
62+
if (this.Layout == null)
63+
{
64+
Formatter.AppendAdditionalLoggingInformation(Config, loggingEvent);
65+
_formattedLog = Formatter.ToJson(loggingEvent);
66+
}
67+
else
68+
{
69+
_formattedLog = Formatter.ToJson(RenderLoggingEvent(loggingEvent), loggingEvent.TimeStamp);
70+
}
71+
72+
//check if logMode is bulk or inputs
73+
if (Config.LogMode == "bulk/")
74+
{
75+
addToBulk(_formattedLog);
76+
}
77+
else if (Config.LogMode == "inputs/")
78+
{
79+
//sending _formattedLog to the async queue
80+
LogglyAsync.PostMessage(_formattedLog, Config);
81+
}
82+
}
83+
84+
public void addToBulk(string log)
85+
{
86+
// store all events into a array max lenght is 100
87+
lstLogs.Add(log.Replace("\n", ""));
88+
if (lstLogs.Count == 100)
89+
{
90+
SendAllEvents(lstLogs.ToArray());
91+
}
92+
}
93+
94+
private void SendAllEvents(string[] events)
95+
{
96+
lstLogs.Clear();
97+
String bulkLog = String.Join(System.Environment.NewLine, events);
98+
LogglyAsync.PostMessage(bulkLog, Config);
99+
}
55100

56101
}
57-
}
102+
}
Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
namespace log4net.loggly
22
{
3-
public class LogglyAppenderConfig: ILogglyAppenderConfig
3+
public class LogglyAppenderConfig : ILogglyAppenderConfig
44
{
55
private string _rootUrl;
6+
private string _logMode;
67
public string RootUrl
78
{
89
get { return _rootUrl; }
@@ -14,9 +15,18 @@ public string RootUrl
1415
{
1516
_rootUrl += "/";
1617
}
17-
if (!_rootUrl.EndsWith("inputs/"))
18+
}
19+
}
20+
21+
public string LogMode
22+
{
23+
get { return _logMode; }
24+
set
25+
{
26+
_logMode = value;
27+
if (!_logMode.EndsWith("/"))
1828
{
19-
_rootUrl += "inputs/";
29+
_logMode = _logMode.ToLower() + "/";
2030
}
2131
}
2232
}
@@ -27,19 +37,20 @@ public string RootUrl
2737

2838
public int TimeoutInSeconds { get; set; }
2939

30-
public string Tag { get; set; }
40+
public string Tag { get; set; }
3141

32-
public string LogicalThreadContextKeys { get; set; }
42+
public string LogicalThreadContextKeys { get; set; }
3343

34-
public string GlobalContextKeys { get; set; }
44+
public string GlobalContextKeys { get; set; }
3545

36-
public LogglyAppenderConfig()
46+
public LogglyAppenderConfig()
3747
{
3848
UserAgent = "loggly-log4net-appender";
3949
TimeoutInSeconds = 30;
40-
Tag = "log4net";
41-
LogicalThreadContextKeys = null;
42-
GlobalContextKeys = null;
50+
Tag = "log4net";
51+
LogMode = "bulk";
52+
LogicalThreadContextKeys = null;
53+
GlobalContextKeys = null;
4354
}
4455
}
4556
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
using System.Collections.Concurrent;
2+
using System.Threading;
3+
4+
namespace log4net.loggly
5+
{
6+
class LogglyAsyncHandler
7+
{
8+
// Size of the internal event queue.
9+
//protected const int QueueSize = 32768;
10+
protected ILogglyAppenderConfig _config;
11+
12+
protected bool IsRunning = false;
13+
//static list of all the queues the le appender might be managing.
14+
private static ConcurrentBag<BlockingCollection<string>> _allQueues = new ConcurrentBag<BlockingCollection<string>>();
15+
16+
public static ILogglyClient Client = new LogglyClient();
17+
public LogglyAsyncHandler()
18+
{
19+
Queue = new BlockingCollection<string>();
20+
_allQueues.Add(Queue);
21+
WorkerThread = new Thread(new ThreadStart(SendLogs));
22+
WorkerThread.Name = "Loggly Log Appender";
23+
WorkerThread.IsBackground = true;
24+
}
25+
26+
protected readonly BlockingCollection<string> Queue;
27+
protected Thread WorkerThread;
28+
29+
protected virtual void SendLogs()
30+
{
31+
if (this._config != null)
32+
{
33+
while (true)
34+
{
35+
var msg = Queue.Take();
36+
Client.Send(this._config, msg);
37+
}
38+
}
39+
}
40+
41+
public void PostMessage(string msg, ILogglyAppenderConfig config)
42+
{
43+
this._config = config;
44+
if (!IsRunning)
45+
{
46+
WorkerThread.Start();
47+
IsRunning = true;
48+
}
49+
if (!Queue.TryAdd(msg))
50+
{
51+
Queue.Take();
52+
Queue.TryAdd(msg);
53+
}
54+
}
55+
}
56+
57+
}

source/log4net-loggly/LogglyBufferringAppender.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@ public class LogglyBufferringAppender : BufferingAppenderSkeleton
1212

1313
private ILogglyAppenderConfig Config = new LogglyAppenderConfig();
1414

15-
public string RootUrl { set { Config.RootUrl = value; } }
16-
public string InputKey { set { Config.InputKey = value; } }
17-
public string UserAgent { set { Config.UserAgent = value; } }
18-
public int TimeoutInSeconds { set { Config.TimeoutInSeconds = value; } }
19-
public string Tag { set { Config.Tag = value; } }
15+
public string RootUrl { set { Config.RootUrl = value; } }
16+
public string InputKey { set { Config.InputKey = value; } }
17+
public string UserAgent { set { Config.UserAgent = value; } }
18+
public string LogMode { set { Config.LogMode = value; } }
19+
public int TimeoutInSeconds { set { Config.TimeoutInSeconds = value; } }
20+
public string Tag { set { Config.Tag = value; } }
2021

2122
protected override void Append(LoggingEvent loggingEvent)
2223
{

source/log4net-loggly/Properties/AssemblyInfo.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,5 @@
3232
// You can specify all the values or you can default the Build and Revision Numbers
3333
// by using the '*' as shown below:
3434
// [assembly: AssemblyVersion("1.0.*")]
35-
[assembly: AssemblyVersion("7.1.0.0")]
36-
[assembly: AssemblyFileVersion("7.1.0.0")]
35+
[assembly: AssemblyVersion("7.2.0.0")]
36+
[assembly: AssemblyFileVersion("7.2.0.0")]

source/log4net-loggly/log4net-loggly.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
<Compile Include="ILogglyAppenderConfig.cs" />
5353
<Compile Include="ILogglyClient.cs" />
5454
<Compile Include="LogglyAppenderConfig.cs" />
55+
<Compile Include="LogglyAsyncHandler.cs" />
5556
<Compile Include="LogglyBufferringAppender.cs" />
5657
<Compile Include="LogglyClient.cs" />
5758
<Compile Include="LogglyFormatter.cs" />

0 commit comments

Comments
 (0)