Search code examples
c#.net-6.0datastage

Parsing DataStage log into C# object


I am trying to figure out an optimal way to parse the following DataStage job log into a C# object:

Event Id: 827
Time    : Mon Nov 14 12:29:35 2022
Type    : STARTED
User    : dsusr
Message Id      : IIS-DSTAGE-RUN-I-0070
Invocation Id   : RANDMONINVOCATIONID
Message :
        Starting Job DS_JOB_NAME.RANDMONINVOCATIONID.
        PS_APPL_Folders = (As pre-defined)
        PS_APPL_Folders.DIR_DATA = /data     (Compiled-in default)
        PS_APPL_Folders.DIR_DATA_IN = files/inputfiles     (Compiled-in default)
        PS_APPL_Folders.DIR_ERR = files/errorfiles     (Compiled-in default)
        PS_APPL_Folders.DIR_REJ = files/rejectfiles     (Compiled-in default)
        PM_FLOW_ID = 0
        $LKP_CUSTOM_ERR_JB_NM = JP_Lookup_Custom_Error
        DSJobController = SQ_Start_Job.RANDMONINVOCATIONID
Event Id: 828
Time    : Mon Nov 14 12:29:35 2022
Type    : INFO
User    : dsusr
Message Id      : IIS-DSTAGE-RUN-I-0126
Invocation Id   : RANDMONINVOCATIONID
Message :
        Environment variable settings:
        _=/usr/bin/nohup
        TDG_STR_StrMin_Length=1
        TDG_STR_StrNewLines=false
        TDG_STR_StrSpaces=false
        TDG_STR_StrSpecial=false
        TDG_STR_StrUpperCase=true
        TDG_TBL_Type=standard
        TDG_Username=fu_uq47ep
        TDG_UserPassword=********
        TDG_UserStory_No=STRY02TEST
Event Id: 829
Time    : Mon Nov 14 12:29:35 2022
Type    : INFO
User    : dsusr
Message Id      : IIS-DSTAGE-RUN-E-0268
Invocation Id   : RANDMONINVOCATIONID
Message :
        DS_JOB_NAME.RANDMONINVOCATIONID: Set NLS locale to US-ENGLISH,US-ENGLISH,US-ENGLISH,US-ENGLISH,US-ENGLISH
Event Id: 830
Time    : Mon Nov 14 12:29:35 2022
Type    : INFO
User    : dsusr
Message Id      : IIS-DSTAGE-RUN-I-0019
Invocation Id   : RANDMONINVOCATIONID
Message :
        DS_JOB_NAME.RANDMONINVOCATIONID.JobControl (@Coordinator): Starting new run of checkpointed Sequence job
Event Id: 831
Time    : Mon Nov 14 12:29:37 2022
Type    : BATCH
User    : dsusr
Message Id      : IIS-DSTAGE-RUN-I-0034
Invocation Id   : RANDMONINVOCATIONID
Message :
        DS_JOB_NAME.RANDMONINVOCATIONID -> _FR_JP_TEST_JOB_CC.RANDMONINVOCATIONID): Job run requested
        Mode (row/warn limits) = 0/0
        Generating operational metadata
        Job Parameters --->
        PM_FLOW_ID=0
        PS_Database=(As pre-defined)
        PS_Folders=(As pre-defined)
        PS_Database=(As pre-defined)
        PS_CustomErrors=(As pre-defined)
        PS_APPL_Folders=(As pre-defined)
        PM_JOB_RUN_ID=123752
        PM_MASTER_SEQUENCE_NM=DS_JOB_NAME
RANDMONINVOCATIONIDDCA8689FE4A3BB45C63E4361AAD61
        $LKP_CUSTOM_ERR_JB_NM=JP_Lookup_Custom_Error
        DSJobController=DS_JOB_NAME.RANDMONINVOCATIONID
Event Id: 832
Time    : Mon Nov 14 12:29:37 2022
Type    : INFO
User    : dsusr
Message Id      : IIS-DSTAGE-RUN-I-0019
Invocation Id   : RANDMONINVOCATIONID
Message :
        DS_JOB_NAME.RANDMONINVOCATIONID.JobControl (DSRunJob): Waiting for job_FR_JP_TEST_JOB_CC.RANDMONINVOCATIONID to start
Event Id: 833
Time    : Mon Nov 14 12:29:38 2022
Type    : INFO
User    : dsusr
Message Id      : IIS-DSTAGE-RUN-I-0019
Invocation Id   : RANDMONINVOCATIONID
Message :
        DS_JOB_NAME.RANDMONINVOCATIONID.JobControl (DSWaitForJob): Waiting for job_FR_JP_TEST_JOB_CC.RANDMONINVOCATIONID to finish
Event Id: 834
Time    : Mon Nov 14 12:29:45 2022
Type    : INFO
User    : dsusr
Message Id      : IIS-DSTAGE-RUN-I-0019
Invocation Id   : RANDMONINVOCATIONID
Message :
        DS_JOB_NAME.RANDMONINVOCATIONID.JobControl (DSWaitForJob): Job_FR_JP_TEST_JOB_CC.RANDMONINVOCATIONID has finished, status = 1 (Finished OK)
Event Id: 835
Time    : Mon Nov 14 12:29:45 2022
Type    : INFO
User    : dsusr
Message Id      : IIS-DSTAGE-RUN-I-0019
Invocation Id   : RANDMONINVOCATIONID
Message :
        DS_JOB_NAME.RANDMONINVOCATIONID.JobControl (@XJS_FR_JP_TEST_JOB_CC): Checkpointed run of job _FR_JP_TEST_JOB_CC.RANDMONINVOCATIONID'
Event Id: 836
Time    : Mon Nov 14 12:29:45 2022
Type    : INFO
User    : dsusr
Message Id      : IIS-DSTAGE-RUN-I-0019
Invocation Id   : RANDMONINVOCATIONID
Message :
        DS_JOB_NAME.RANDMONINVOCATIONID.JobControl (@Coordinator): Removed checkpoint record at successful completion of sequence
Event Id: 837
Time    : Mon Nov 14 12:29:45 2022
Type    : INFO
User    : dsusr
Message Id      : IIS-DSTAGE-RUN-I-0019
Invocation Id   : RANDMONINVOCATIONID
Message :
        DS_JOB_NAME.RANDMONINVOCATIONID.JobControl (@Coordinator): Summary of sequence run
        12:29:35: Sequence started (checkpointing on)
        12:29:36: XJS_FR_JP_TEST_JOB_CC (JOB_FR_JP_TEST_JOB_CC.RANDMONINVOCATIONID) started
        12:29:45: XJS_FR_JP_TEST_JOB_CC (JOB_FR_JP_TEST_JOB_CC.RANDMONINVOCATIONID) finished, status=1 [Finished OK]
        12:29:45: Sequence finished OK
Event Id: 838
Time    : Mon Nov 14 12:29:45 2022
Type    : STARTED
User    : dsusr
Message Id      : IIS-DSTAGE-RUN-I-0077
Invocation Id   : RANDMONINVOCATIONID
Message :
        Finished Job DS_JOB_NAME.RANDMONINVOCATIONID.

I've defined the following class:

public class JobLog
{
        public int EventId { get; set; }
        public DateTime Time { get; set; }
        public string Type { get; set; }
        public string User { get; set; }
        public string MessageId { get; set; }
        public string InvocationId { get; set; }
        public string Message { get; set; }
}

I was thinking to split the log by \r\n and check if the line contains the word Event Id then assign the value to the EventId property, and so on. My problem is with the message property, since it can include multiple lines. How should the logic be here?

    private void ParseLog()
    {
            var log = GetSampleLog()
                    .Split("\r\n");

            foreach (var line in log)
            {
                    if (line.Contains("Event Id:", StringComparison.InvariantCultureIgnoreCase))
                    {
                            var logObj = new JobLog
                            {
                                    EventId = int.Parse(line.Split(":")[1])
                            };
                    }
            }
    }

Solution

  • This is my solution :

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Xml;
    using System.IO;
    using System.Globalization;
    
    namespace ConsoleApplication51
    {
        class Program
        {
            const string FILENAME = @"c:\temp\test.txt";
            static void Main(string[] args)
            {
                string line = "";
                StreamReader reader = new StreamReader(FILENAME);
    
                List<Event> events = new List<Event>();
                Event _event = null;
                string[] splitArray = null;
                Boolean getMessages = false;
                while ((line = reader.ReadLine()) != null)
                {
                    line = line.Trim();
                    if (line.Length > 0)
                    {
                        if (line.StartsWith("Event Id"))
                        {
                            splitArray = line.Split(new char[] { ':' });
                            _event = new Event();
                            events.Add(_event);
                            _event.eventID = splitArray[1].Trim();
                            getMessages = false;
                            continue;
                        }
                        if (line.StartsWith("Time"))
                        {
                            int startOfDate = line.IndexOf(":") + 6;
                            string date = line.Substring(startOfDate).Trim();
                            _event.date = DateTime.ParseExact(date,"MMM dd HH:mm:ss yyyy", CultureInfo.InvariantCulture);
                            continue;
                        }
                        if (line.StartsWith("Type"))
                        {
                            splitArray = line.Split(new char[] { ':' });
                            _event.type = splitArray[1].Trim();
                            continue;
                        }
                        if (line.StartsWith("User"))
                        {
                            splitArray = line.Split(new char[] { ':' });
                            _event.user = splitArray[1].Trim();
                            continue;
                        }
                        if (line.StartsWith("Message Id"))
                        {
                            splitArray = line.Split(new char[] { ':' });
                            _event.messageID = splitArray[1].Trim();
                            continue;
                        }
                        if (line.StartsWith("Invocation Id"))
                        {
                            splitArray = line.Split(new char[] { ':' });
                            _event.InvocationID = splitArray[1].Trim();
                            continue;
                        }
                        if(line.StartsWith("Message"))
                        {
                            getMessages = true;
                            continue;
                        }
                        if (getMessages)
                        {
                            if(_event.messages == null)
                               _event.messages = new List<string>();
                            _event.messages.Add(line.Trim());
    
                        }
                    }
                }
            }
        }
        public class Event
        {
            public string eventID { get; set; }
            public DateTime date { get; set; }
            public string type { get; set; }
            public string user { get; set; }
            public string messageID { get; set; }
            public string InvocationID { get; set; }
            public List<string> messages { get; set; }
        }
     
    }