0

I am writing a SysLog Server where my program receive messages of RFC5424Format.

My program has to parse the message and store the values.

I have got a regular expression which is failing to parse the message.

There is problem in Regular Expression.I am new to Regular expression.

Any help appreciated.

public static void Main()
    {
        string RFC5424Format = @"(\<(?<PRI>\d+)\>(?<VERSION>\d+)?)? \ * (?<TIMESTAMP> ( (?<YEAR>\d+) - (?<MONTH>\d+) - (?<DAY>\d+) ) T+ (?<HOUR>\d+): (?<MINUTE>\d+): (?<SECOND>\d+) (\.(?<MILLISECONDS>\d+))? (?<OFFSET>Z|(\+|\-)\d+:\d+)? ) \ (?<HOSTNAME>[\w!-~]+) \ (?<APPNAME>[\w!-~]+) \ (?<PROCID>[\w!-~]+) \ (?<MSGID>[\w!-~]+) \  (?<SD>-|(\[.*\])) \ ?(?<MESSAGE>.*)?";

        Regex rfc5424 = new Regex("^" + RFC5424Format + "$", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.IgnorePatternWhitespace);

        string input = "< 38 > 1 2018 - 03 - 01T16: 05:51.799465 + 05:30 AAEINBLR07229L Source_UDP - -\n ??? MessageContent_Via_UDP - 5424";

        Match m = rfc5424.Match(input);

        if (m.Success)
        {
            Console.WriteLine("Regex is fine");
        }
        else
        {
            Console.WriteLine("Problem in Regex");
        }
    }
reddy
  • 173
  • 1
  • 4
  • 9
  • Please provide some examples and what's right and whats wrong. With only the one example given (I guess this should match) we got nothing else to check our answers or answer properly – Chrᴉz remembers Monica Mar 01 '18 at 14:28

2 Answers2

2

I just came across this problem recently. According to RFC 5424, the Syslog message should be in the following format: HEADER SP STRUCTURED-DATA [SP MSG], where SP is a space character and the brackets represent the data is optional. Having said that I found it easier to break the message down into three separate regular expression patterns and then combine them when I instantiate a Regex object for comparing.

Here's my sample class. I hope it helps.

public class SyslogMessage
{
    private static readonly string _SyslogMsgHeaderPattern = @"\<(?<PRIVAL>\d{1,3})\>(?<VERSION>[1-9]{0,2}) (?<TIMESTAMP>(\S|\w)+) (?<HOSTNAME>-|(\S|\w){1,255}) (?<APPNAME>-|(\S|\w){1,48}) (?<PROCID>-|(\S|\w){1,128}) (?<MSGID>-|(\S|\w){1,32})";
    private static readonly string _SyslogMsgStructuredDataPattern = @"(?<STRUCTUREDDATA>-|\[[^\[\=\x22\]\x20]{1,32}( ([^\[\=\x22\]\x20]{1,32}=\x22.+\x22))?\])";
    private static readonly string _SyslogMsgMessagePattern = @"( (?<MESSAGE>.+))?";
    private static Regex _Expression = new Regex($@"^{_SyslogMsgHeaderPattern} {_SyslogMsgStructuredDataPattern}{_SyslogMsgMessagePattern}$", RegexOptions.None, new TimeSpan(0, 0, 5));
    
    public int Prival { get; private set; }
    public int Version { get; private set; }
    public DateTime TimeStamp { get; private set; }
    public string HostName { get; private set; }
    public string AppName { get; private set; }
    public string ProcId { get; private set; }
    public string MessageId { get; private set; }
    public string StructuredData { get; private set; }
    public string Message { get; private set; }
    public string RawMessage { get; private set; }

    /// <summary>
    /// Parses a Syslog message in RFC 5424 format. 
    /// </summary>
    /// <exception cref="FormatException"></exception>
    /// <exception cref="OverflowException"></exception>
    /// <exception cref="ArgumentNullException"></exception>
    /// <exception cref="InvalidOperationException"></exception>
    public static SyslogMessage Parse(string rawMessage)
    {
        if (string.IsNullOrWhiteSpace(rawMessage)) { throw new ArgumentNullException("message"); }

        var match = _Expression.Match(rawMessage);
        if (match.Success)
        {
            return new SyslogMessage
            {
                Prival = Convert.ToInt32(match.Groups["PRIVAL"].Value),
                Version = Convert.ToInt32(match.Groups["VERSION"].Value),
                TimeStamp = Convert.ToDateTime(match.Groups["TIMESTAMP"].Value),
                HostName = match.Groups["HOSTNAME"].Value,
                AppName = match.Groups["APPNAME"].Value,
                ProcId = match.Groups["PROCID"].Value,
                MessageId = match.Groups["MSGID"].Value,
                StructuredData = match.Groups["STRUCTUREDDATA"].Value,
                Message = match.Groups["MESSAGE"].Value,
                RawMessage = rawMessage
            };
        }
        else { throw new InvalidOperationException("Invalid message."); }
    }

    public override string ToString()
    {
        var message = new StringBuilder($@"<{Prival:###}>{Version:##} {TimeStamp.ToString("yyyy-MM-ddTHH:mm:ss.fffK")} {HostName} {AppName} {ProcId} {MessageId} {StructuredData}");

        if (!string.IsNullOrWhiteSpace(Message))
        {
            message.Append($" {Message}");
        }

        return message.ToString();
    }
}
Community
  • 1
  • 1
0

Regex always needs a lot of thinking and testing to get right. I do not have time to fix it all, but I can tell you you are almost on the right track. I have rewritten and tested part of the Regex (with no anchoring) and am including it here for reference:

\< *(?<PRI>\d+) *\> *(?<VERSION>\d+)? *(?<YEAR>\d+) - (?<MONTH>\d+) - (?<DAY>\d+)T(?<HOUR>\d+): *(?<MINUTE>\d+):(?<SECOND>\d+)\.(?<MILLISECONDS>\d+) *\+ *(?<OFFSET>\d+:\d+) *(?<HOSTNAME>\b\w+\b) *(?<SOURCE>\b\w+\b)

I have always found https://www.regexpal.com/ to be helpful in debugging Regex issues. Just take it slow, step by step approach. Let me know how it works out!

Alexandru Clonțea
  • 1,746
  • 13
  • 23