Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Community discussion is present here: http://community.pbspro.org/t/pp-838-support-for-logging-via-syslog-in-pbs/591


Table of Contents

...

Overview

PBS currently has a facility for logging via syslog. We are reverse engineering to the EDD. We need to have the use cases, test scenarios and test cases (both manual and PTL) reviewed by the open source communityhave to add support to PTL to test the syslog functionality of PBS.

Use Cases

1. As an admin, I should be able to set PBS logging via syslog so that all daemons log into the same file.

2.  As an admin, I should be able to control log events level of the PBS logging.

3.  As an admin, I should be able to set the logging via syslog for all nodes in the cluster

4.  As an admin, I should be able to set the logging via syslog for all servers in a failover environment.

5. As a admin I should be able to have logging into both local daemons and Syslog enabled together

6.  As an admin/user, I should be able to run tracejob for a specific job with Syslog.
Note- This functionality is not currently given by PBS. This is added here because it is nice enhancement for future use.

7.  As an admin/user, I should be able to differentiate log messages from each daemon.

8. As an admin/user, I should be able to set logging via syslog for only a particular daemon (Server, Mom, Sched or Comm). 



Design


The design for adding syslog matching is been written so that there minimal changes for existing functionality.

1) The same log_match() functions for each class (Server, MoM, Sched and Comm) are been used with changes to read into syslog. For example to check server messages that go into syslog we will have the same method server.log_match(). This will also help the tests differentiate the messages from individual daemons.

PTL will read into syslog in these cases-

1) syslog parameter is set in log_match() function

2) PBS_SYSLOG is set in pbs.conf. This case is for running the existing PTL tests which do not have syslog parameter in log_match().

function will be used. PTL will check the pbs.conf file for syslog setting.

2) PTL will match the messages according to the daemon. For eg: server.logmatch() will match only server log messages from syslog.

3) Multihost support is provided. syslog messages from individual hosts will be read.


Things to be taken into consideration-

We should make sure that the user running the tests will  have permissions to read syslog file and decompress it. For eg - in test bed machine pbsroot shoud be able to read from syslog file. .

New flow of log_match() with syslog support-

Image Added


For adding syslog support in PTL we will have to make changes in two files-  pbs_logutils.py and pbs_testlib.py. 

A new class syslog_utils is added for reading the date, syslog file path and the logic for which log messages file to check.

———————syslog_utils.py——————

To add the functionality on which logs to check in log_match(), syslog or local logs we will follow this table -

PBS_SYSLOG  and PBS_LOCALLOG are values from the pbs.conf file. Syslog_attribute is the attribute to be passed to the log_match() function. Return value is the return value of log_match()

...

PBS_SYSLOG  

...

PBS_LOCALLOG  

...

Syslog_attribute 

...

Which log to check in log_match() 

...

Not_set 

...

0 

...

0 

...

Throw error

...

Not_set 

...

0 

...

1 

...

Throw error 

...

Not_set 

...

1 

...

0 

...

Local_Log 

...

Not_set 

...

1 

...

1 

...

Throw error 

...

set 

...

0 

...

0 

...

Syslog 

...

set 

...

0 

...

1 

...

Syslog 

...

set 

...

1 

...

0 

...

Match in both logs 

...

set 

...

1 

...

1 

...

Syslog 

...

 

In row 7 where we have to match in both syslog and local log, we would have to call _log_match() twice. 

Note: Currently we are only supporting for the current syslog file and not for previous days file. That would be covered in PP-969 

import platform

class syslog_utils(object):

    du = DSHUtils()

   # Syslog conf file data path

    syslog_conf_path = {'rsyslogd': '/etc/rsyslog.conf', 'syslog-ng': '/etc/syslog-ng/syslog-ng.conf'}

    # PBS supported severity and facilities
    p_severity = ['info', 'debug']
    p_facility = ['*', 'local7', ....]    

   

    facility = //PBS_SYSLOG from pbs.conf

    serverity = //  PBS_SYSLOGSEVR from pbs.conf (by default NONE)

    

    

    def log_config_values(syslog=0)

       // logic for which file to read will come from the above table

      // returns a integer value which is interpreted as which file to check

       self.file_to_check=0

       // read from PBS.conf  PBS_SYSLOG & PBS_LOCALLOG

      // Logic of which file to read log messages from- syslog or local

      // file_to_check =1 for syslog, file_to_check=2 for local logs  and file_to_check=3 for both

      return self.file_to_check

    

    def log_syslog_lines(self):

        //This function returns the syslog messages for logmatch

        # get syslog utility running and conf file

        self.cmd_sys = "ps -e | grep syslog | awk '{print $NF}'"

        self.utility = self.du.run_cmd(hosts=hostname, cmd=self.cmd_sys, as_script=True, sudo=True,

                                level=logging.DEBUG2)['out']

        self.syslog_conf_file = self.syslog_conf_path.get(self.utility[0])

        #get syslog log files to be read.

        list_of_priority = []

        if self.utility[0] == "rsyslogd":

            list_of_priorities = self.get_rsyslog_priorites(severity=severity, facility=facility)

            self.list_of_syslog_files = self.get_rsyslog_files(list_of_priorities)

        elif self.utility[0] == "syslog-ng":

            list_of_priorities = self.get_syslogng_priorites(severity=severity, facility=facility)

            self.list_of_syslog_files = self.get_syslogng_files(list_of_priorities)

        else: 

            // throw error

           // PtlLogMatchError(rc=1, rv=False, msg=_msg)   

       # Get lines from each of the files from list_of_syslog_files[]

        lines = []

        combined_lines = []

        for x in self.list_of_syslog_files:

            l_sys = self.get_syslog_lines(hostname=hostname, n=n, filename=x, logval=logval)

            lines.append(l_sys)

        # combine lines from each file

        combined_lines = [item for sublist in lines for item in sublist]

        

        # Sort lines by datetime

        combined_lines.sort(key=lambda x: datetime.datetime.strptime(x[:15], "%b %d %H:%M:%S"))

        return combined_lines

    

    def ———————In pbs_logutils.py——————

Class PBSLogUtils(object):

 

New methods:       

    def _get_syslog_lines(hostname, n, logval):

        Summary: This function returns the syslog messages for logmatch

        Input:

        #hostname = host from which to read syslog file

        # n= number of lines requested by user  

        # logval - sched/server/mom/comm logs 

       

       Description:

  1.  get type of syslog utility (rsyslog/syslog-ng) running on host and syslog conf file. Currently we are only supporting rsyslog and not syslog-ng
  2. get PBS_SYSLOGSEVR from pbs.conf. If it is not set throw error PBSConfigError that set PBS_SYSLOGSEVR
  3. According to utility get list_of_priorites[] (severity + facility) - _get_rsyslog_priorites()
  4. With the priorities get list_of_syslog_files[]  (if there is no list of files returned, throw PTL error) _get_rsyslog_files()
  5. Get lines from each of the files in list_of_syslog_files[] . This will consider the n and logval arguments. Only the specified logval messages will be considered
    If no lines are returned throw PTLerror
  6. Combine and Sort lines by datetime


      return: Sorted +  combined_lines (This list of lines will be used by the match_msg() for log_match

    

    def _get_rsyslog_priorites(self, severity=None, facility=None)

        # Summary: Returns the priorities. Since the syslog messages can be stored in multiple files, a list is returned

        # If facility and severity mentioned return the file for that combination from rsyslog.conf

        # If severity is NONE read into rsyslog.conf file and return all priotities that contain the severity set in rsyslogd.conf

        return list_of_priorities[]

       

    def get_syslogng_priorites(self, severity=None, facility=None)

        # Returns the priorities. Since the syslog messages can be stored in multiple files, a list is returned

        # If facility and severity mentioned return the file for that combination from rsyslog.conf

        # If severity is NONE read into rsyslog.conf file and return all priotities that contain the severity set in syslog-ng.conf

          Input: severity and facilty values

        return list_of_priorities[]

    

    def _get_rsyslog_files(self, list_of_priorities[])

        # Summary: Returns the path of files to be read on basis of the priorities. Since the syslog messages can be stored in multiple files, a list is returned

        return list_of_files[] Input:

    def get_syslog_ng_files(self, list    list_of_priorities[])

        # Returns the path of files to be read on basis of the priorities. Since the syslog messages can be stored in multiple files, a list is returned         return list_of_files[]

    def get_syslog_lines(self, hostname=None, n=50, filename=None, logval=None):

        # Return the last block of lines from the syslog files for that particular daemon

        # n= number of lines requested by user

        #hostname = host from which to read syslog file

        # file name is the file to read

        

        # is user says all lines, default to 100

        if n == "ALL":


// Changes to existing methods in PBSLogUtils class

    def convert_date_time(syslog=false)    

   Description: If the syslog files are to be read the date format in the lines changes. Currently the fmt is set to the default syslog fmt

         if syslog: 

             fmt=syslog_format

         fmt is later passed to strptime funtion.


    def match_msg(syslog=false) 

   Description: If the syslog message lines are to be read the match_msg() will check the list of syslog lines

        if syslog:            n=100

         

...

  date_length = //length according to date format (by default set to 15)

        if

...

lines:

           

...

for l in lines:

             

...

 if starttime is not None:

           

...

     

...

tm = self.convert_date_time(l[:date_length], syslog=syslog)

       

...

     

...

if endtime is not None:

           

...

        elif logval is 'comm_logs':

            daemon_str = 'pbs_comm'

        else:

            // PtlLogMatchError(rc=1, rv=False, msg=_msg)  

       

        # use tail command to get last block of lines from file

        cmd = ['/usr/bin/tail']

        cmd += [str(n), filename]

        lines = self.du.run_cmd(hosts=hostname, cmd=cmd, sudo=True,

                                level=logging.DEBUG2)['out']

        lines = [l for l in lines if daemon_str in l]

        return lines

————pbs_testlib.py——————————

Following changes are done to the current log_match() function

1) log_match() calls the _log_match() method. 

Therefore according to the table above we should have a conditional statements in log_match()

In case both have to be read we should call the _log_match() twice.

class PBSService(PBSObject)

   def log_match(syslog=False)

       // Additions: Get the value of whether to read syslog or locallog files

      if syslog:      

          x= syslog_config.log_config_values(syslog=true)

     

      // Values to pass to _log_match() 

       if x==1

           return _log_match(syslog=true)

      elif x==2

           return _log_match(syslog=false)

      elif x==3 

...

     tm = self.convert_date_time(l[:date_length], syslog=syslog)



Changes to existing methods are made in the following files:- 


————pbs_testlib.py——————————


class PBSService(PBSObject)

   New method 

  def _get_log_type()

       Summary: logic for which messages to read (local logs / syslog)

      Description: 

      1) read from PBS.conf  - PBS_SYSLOG & PBS_LOCALLOG.  

      2) Logic for whether to read local logs/ syslog we will follow this table -

           

     


PBS_SYSLOG  

PBS_LOCALLOG  

Which log to check in log_match() 

0 

Throw error

1

Local_log

set (1-7)

0

Syslog 

set (1-7)

1 

 Match in both logs 

unsetunsetLocal_log






       Note: In row 4 where we have to match in both syslog and local log, we would have to call _log_match() twice. 

       Note: In case of row 4 the return value for log_match() will return lines from local_logs only.

       Note: Currently we are only supporting for the current syslog file and not for previous days file. That would be covered in PP-969 

      Note:  The error thrown will be PtlLogMatchError     

       Return:      

      self.file_to_check (/ / file_to_check =1 for syslog, file_to_check=2 for local logs  and file_to_check=3 for both)



   def log_match()

      Description:

        1) self._get_log_type() to check if local logs/ syslog is to be checked

          x= PBSLogUtils._get_log_type(syslog=syslog)

       2) if x =1 or 3 -  read _log_match(syslog=true) 

      3) if x = 2 or 3 -    // Read in local logs only if syslog log match is returned true. If syslog fails there is no need to check in local logs  read _log_match(syslog=false)

          if syslog_return:   4) if x=3 then - if step 2 and step 3 pass return the value

     

       return

  def _log_match(syslog=falseFalse)

   // Additions: 

    else:

            return syslog_return

      else:

         _msg= "Log file to check not set"

         PtlLogMatchError(rc=1, rv=False, msg=_msg)        

  def _log_match(syslog=False)

       syslog: If the user wants to read into syslog file? By default false

   

    Description:

    The syslog value is further passes to log_lines() and match_msg()      

    lines = self.log_lines(syslog=true)

      rv = self.logutils.match_msg(syslog=true)


Note- 'def log_lines' returns the last n lines of the log file.

 def log_lines(syslog=False)

 syslog: If the user wants to read into syslog file?       logval = None         lines = None

        sudo = False

        self.syslogUtils = syslog_utils()

 Description: 

        if syslog:

           logval = self._instance_to_logpath(logtype)

           lines = self.syslogUtilsPBSLogUtils.log_get_syslog_lines(hostname=self.hostname, n=n, logval=logval)

——————————In pbs_logutils.py—————————————

Class PBSLogUtils(object)

     def convert_date_time(syslog=false)

         if syslog: 

             fmt="%b %d %H:%M:%S"

         try:

             t = time.strptime(datetime, fmt)

             if syslog:   

...

)


           

...

               t_edit = list(t)
               t_edit[0]= int(split_now[0])
               t = time.struct_time(tuple(t_edit))

     def match_msg(syslog=false)

         if syslog:           

            date_length = //length according to date format (by default set to 15)

       

        if lines:

            for l in lines:

               if starttime is not None:

                  tm = self.convert_date_time(l[:date_length], syslog_flag=syslog)

              if endtime is not None:

                 tm = self.convert_date_time(l[:date_length], syslog_flag=syslog)

           


Test Scenarios

1) Test that when PBS_SYSLOG=1 is enabled in pbs.conf, PBS logs messages via syslog.

2) Test that according to the PBS_SYSLOGSEVR value in pbs.conf the messages of that severity are logged via syslog. This should include tests for each severity level- Emergency, alert , critical, error, warning, notice, informational, debug.

3) Test that in a multi-node cluster setup, logging via syslog can be enabled. 

4) Test that in a failover environment logging via syslog works on all the servers.

5) Test that both local logging and logging via syslog can be enabled simultaneously for both, single node and execution nodes in a cluster.

6) Test that tracejob works when logging via syslog is enabled 

(Note: trace job currently does not work with Syslog. Since this is a use case and would be a nice enhancement to have)

7) Test that server and sched and mom messages can be differentiated explicitly in the syslog log file.

8) Check that there is no performance issue with large log files 

8) Test that logging via sys logging can be set for only a particular daemon.
(This functionality is not present in PBS)

Glossary

Wiki page for syslog