Skip to content

Commit 3fd0979

Browse files
committed
Merge pull request #1 from tetious/feature/cleanups
Refactoring and cleanups.
2 parents 378acd7 + 6d4372c commit 3fd0979

File tree

16 files changed

+418
-128
lines changed

16 files changed

+418
-128
lines changed

src/SyslogProxy/App.config

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
<?xml version="1.0" encoding="utf-8" ?>
22
<configuration>
3+
<appSettings>
4+
<add key="SeqServer" value="http://localhost:5341"/>
5+
<add key="MessageTemplate" value="{Hostname}:{ApplicationName} {Message}"/>
6+
</appSettings>
37
<startup>
48
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
59
</startup>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
namespace SyslogProxy
2+
{
3+
using System.Collections;
4+
using System.Configuration.Install;
5+
using System.Diagnostics;
6+
7+
public class EventSourceInstaller : Installer
8+
{
9+
public override void Install(IDictionary stateSaver)
10+
{
11+
if (!EventLog.SourceExists(Logger.EventSource))
12+
{
13+
EventLog.CreateEventSource(Logger.EventSource, "Application");
14+
}
15+
16+
base.Install(stateSaver);
17+
}
18+
19+
public override void Rollback(IDictionary savedState)
20+
{
21+
if (EventLog.SourceExists(Logger.EventSource))
22+
{
23+
24+
}
25+
26+
base.Rollback(savedState);
27+
}
28+
}
29+
}

src/SyslogProxy/Logger.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
namespace SyslogProxy
2+
{
3+
using System.Diagnostics;
4+
5+
public static class Logger
6+
{
7+
public const string EventSource = "SyslogProxy";
8+
9+
public static void Information(string message, params object[] args)
10+
{
11+
Information(string.Format(message, args));
12+
}
13+
14+
public static void Warning(string message, params object[] args)
15+
{
16+
Warning(string.Format(message, args));
17+
}
18+
19+
public static void Error(string message, params object[] args)
20+
{
21+
Error(string.Format(message, args));
22+
}
23+
24+
public static void Information(string message)
25+
{
26+
EventLog.WriteEntry(EventSource, message, EventLogEntryType.Information);
27+
}
28+
29+
public static void Warning(string message)
30+
{
31+
EventLog.WriteEntry(EventSource, message, EventLogEntryType.Warning);
32+
}
33+
34+
public static void Error(string message)
35+
{
36+
EventLog.WriteEntry(EventSource, message, EventLogEntryType.Error);
37+
}
38+
}
39+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
namespace SyslogProxy.Messages
2+
{
3+
using System;
4+
using System.Configuration;
5+
6+
public static class Configuration
7+
{
8+
public static Uri SeqServer
9+
{
10+
get
11+
{
12+
var seqServer = ConfigurationManager.AppSettings["SeqServer"];
13+
return string.IsNullOrWhiteSpace(seqServer) ? null : new Uri(seqServer);
14+
}
15+
}
16+
17+
public static string MessageTemplate
18+
{
19+
get
20+
{
21+
return ConfigurationManager.AppSettings["MessageTemplate"];
22+
}
23+
}
24+
25+
public static int ProxyPort
26+
{
27+
get
28+
{
29+
return IntOrDefault(ConfigurationManager.AppSettings["ProxyPort"], 6514);
30+
}
31+
}
32+
33+
public static int TcpConnectionTimeout
34+
{
35+
get
36+
{
37+
return IntOrDefault(ConfigurationManager.AppSettings["TcpConnectionTimeout"], 60 * 10);
38+
}
39+
}
40+
41+
public static void Validate()
42+
{
43+
if (SeqServer == null)
44+
{
45+
throw new InvalidOperationException("SeqServer is null or empty.");
46+
}
47+
48+
if (string.IsNullOrWhiteSpace(MessageTemplate))
49+
{
50+
throw new InvalidOperationException("MessageTemplate is null or empty.");
51+
}
52+
}
53+
54+
private static int IntOrDefault(string candidate, int orDefault)
55+
{
56+
int parsedInt;
57+
return int.TryParse(candidate, out parsedInt) ? parsedInt : orDefault;
58+
}
59+
}
60+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace SyslogProxy
1+
namespace SyslogProxy.Messages
22
{
33
public enum Facility
44
{
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
namespace SyslogProxy.Messages
2+
{
3+
using System;
4+
using System.Linq;
5+
using System.Text.RegularExpressions;
6+
7+
using Newtonsoft.Json;
8+
9+
public class JsonSyslogMessage
10+
{
11+
private static readonly Regex DateStampRegex = new Regex(@"\w{3} \w{3}.{4}\d{2}:\d{2}:\d{2}.\d{3}");
12+
13+
public JsonSyslogMessage(string rawMessage)
14+
{
15+
this.RawMessage = rawMessage;
16+
17+
var splitLine = rawMessage.Split(' ');
18+
if (splitLine.Length < 4)
19+
{
20+
this.Invalid = true;
21+
return;
22+
}
23+
24+
try
25+
{
26+
var priority = int.Parse(splitLine[0]);
27+
var facility = priority / 8;
28+
var severity = priority % 8;
29+
30+
this.Facility = ((Facility)facility).ToString();
31+
this.Level = ((Severity)severity).ToString();
32+
}
33+
catch (Exception)
34+
{
35+
Logger.Warning("Could not parse priority. [{0}]", rawMessage);
36+
this.Invalid = true;
37+
return;
38+
}
39+
40+
DateTime notUsed;
41+
this.Invalid = !DateTime.TryParse(splitLine[1], out notUsed);
42+
43+
this.Timestamp = splitLine[1];
44+
this.Hostname = splitLine[2].Trim();
45+
this.ApplicationName = splitLine[3].Trim();
46+
this.Message = DateStampRegex.Replace(string.Join(" ", splitLine.Skip(4)).Trim(), string.Empty).Trim();
47+
}
48+
49+
public bool Invalid { get; private set; }
50+
51+
public string RawMessage { get; private set; }
52+
53+
public string Timestamp { get; set; }
54+
55+
public string Level { get; set; }
56+
57+
public string Facility { get; set; }
58+
59+
public string Hostname { get; set; }
60+
61+
public string ApplicationName { get; set; }
62+
63+
public string Message { get; set; }
64+
65+
public override string ToString()
66+
{
67+
return JsonConvert.SerializeObject(new SeqEventMessage()
68+
{
69+
Level = this.Level,
70+
Timestamp = this.Timestamp,
71+
MessageTemplate = Configuration.MessageTemplate,
72+
Properties = new { this.Facility, this.Hostname, this.ApplicationName, this.Message }
73+
});
74+
}
75+
}
76+
}

src/SyslogProxy/SeqEvent.cs renamed to src/SyslogProxy/Messages/SeqEventMessage.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
namespace SyslogProxy
1+
namespace SyslogProxy.Messages
22
{
3-
public class SeqEvent
3+
public class SeqEventMessage
44
{
55
public string Timestamp { get; set; }
66

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace SyslogProxy
1+
namespace SyslogProxy.Messages
22
{
33
public enum Severity
44
{

src/SyslogProxy/Program.cs

Lines changed: 19 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,28 @@
11
namespace SyslogProxy
22
{
3-
using System;
4-
using System.Net;
5-
using System.Net.Http;
6-
using System.Net.Sockets;
7-
using System.Text;
8-
using System.Threading;
9-
using System.Threading.Tasks;
3+
using System.Collections.Generic;
4+
using System.ComponentModel;
5+
using System.ServiceProcess;
106

11-
public class Program
7+
using SimpleServices;
8+
9+
[RunInstaller(true)]
10+
public class Program : SimpleServiceApplication
1211
{
1312
static void Main(string[] args)
1413
{
15-
var tcp = new TcpListener(IPAddress.Any, 6514);
16-
17-
tcp.Start();
18-
AcceptConnection(tcp);
19-
while (true)
20-
{
21-
Thread.Sleep(10000);
22-
}
23-
}
24-
25-
static async Task AcceptConnection(TcpListener listener)
26-
{
27-
while (true)
28-
{
29-
var client = await listener.AcceptTcpClientAsync().ConfigureAwait(false);
30-
EchoAsync(client);
31-
}
32-
}
33-
34-
static async Task EchoAsync(TcpClient client)
35-
{
36-
Console.WriteLine("New client connected.");
37-
using (client)
38-
{
39-
var buf = new byte[4096];
40-
var stream = client.GetStream();
41-
while (true)
42-
{
43-
var timeoutTask = Task.Delay(TimeSpan.FromSeconds(15));
44-
var amountReadTask = stream.ReadAsync(buf, 0, buf.Length);
45-
var completedTask = await Task.WhenAny(timeoutTask, amountReadTask)
46-
.ConfigureAwait(false);
47-
if (completedTask == timeoutTask)
48-
{
49-
Console.WriteLine("Client timed out");
50-
break;
51-
}
52-
53-
var amountRead = amountReadTask.Result;
54-
if (amountRead == 0) break; //end of stream.
55-
// stuff buff into a json thing
56-
await WriteToSeq(new SyslogJson(Encoding.UTF8.GetString(buf).TrimEnd('\0')));
57-
}
58-
}
59-
Console.WriteLine("Client disconnected");
60-
}
61-
62-
public static async Task WriteToSeq(SyslogJson syslog)
63-
{
64-
using (var http = new HttpClient())
65-
{
66-
using (var content = new StringContent("{\"events\":[" +syslog.ToString() + "]}", Encoding.UTF8, "application/json"))
67-
{
68-
var response = await http.PostAsync("http://10.2.10.156:5341/api/events/raw", content);
69-
if (!response.IsSuccessStatusCode)
70-
{
71-
Console.WriteLine("ERROR: Could not send to SEQ.");
72-
}
73-
}
74-
}
14+
new Service(args,
15+
new List<IWindowsService> { new ProxyService() }.ToArray,
16+
installationSettings: (serviceInstaller, serviceProcessInstaller) =>
17+
{
18+
serviceInstaller.ServiceName = "SyslogProxy";
19+
serviceInstaller.Description = "A simple Syslog proxy for Seq.";
20+
serviceInstaller.StartType = ServiceStartMode.Automatic;
21+
serviceProcessInstaller.Account = ServiceAccount.LocalService;
22+
serviceProcessInstaller.Installers.Add(new EventSourceInstaller());
23+
},
24+
configureContext: x => { x.Log = Logger.Information; })
25+
.Host();
7526
}
7627
}
7728
}

0 commit comments

Comments
 (0)