Share via


Managing Client Log File Size for the UNIX and Linux Configuration Manager Clients

Details about the log files created by the UNIX and Linux Clients for System Center 2012 R2 Configuration Manager can be found in this article. The UNIX and Linux clients do not rotate or manage the size of the client log files. Where possible, such as on Linux systems, it is recommended to use system tools such as logrotate to manage the Configuration Manager client log files.  However, logrotate is not available on all operating systems supported by the Client.  For cases where logrotate is not available, the following example script can be distributed and scheduled to rotate Configuration Manager Client log files.   This example script is viable for all UNIX and Linux operating systems supported by the Configuration Manager Client.

Deploying the script
Configuration Manager's software distribution is an ideal mechanism to deploy the script to managed UNIX or Linux clients.  To deploy the script with software distribution, create a package with the script contained in the package's source directory, and use a command such as: /bin/sh -c "cp logrotate.sh /opt/microsoft/configmgr/bin/" as the program.  This command would copy the file named logrotate.sh to the default bin directory for the client.

Scheduling the script
The cron daemon is a good mechanism for regular scheduling of the log rotation script.  A cron job can be scheduled daily, weekly, or monthly to rotate the Configuration Manager clients and retain a specified number of archived logs to keep.  If software distribution is used to deploy the script to the clients, a crontab file can also be distributed with the script or the package can invoke a script or command to edit the active crontab file.

Example Log Rotation Script

#!/bin/sh
# This file is expected to be placed in CM's bin directory, and run from that directory since this script uses relative paths.
# Usage:
#     logrotate NUMBER_OF_LOGS_TO_KEEP
# where NUMBER_OF_LOGS_TO_KEEP is a postive integer
CM_DIR=..
OMI_DIR=../../omi
OMI_LOGDIR=$OMI_DIR/var/log

if [ -x /usr/xpg4/bin/awk ]; then
    AWK=/usr/xpg4/bin/awk
else
    AWK=awk
fi

CCM_IS_RUNNING=0
OMI_IS_RUNNING=0
if [ -f "$CM_DIR/CCMExec.pid" ]; then   
    pid=`cat $CM_DIR/CCMExec.pid`

    ps -aef | $AWK -v OFS=',' '{ print $2,$8 }' | grep "^$pid" | grep "ccmexec" 1> /dev/null
    if [ $? -eq 0 ]; then
 CCM_IS_RUNNING=1
    fi
fi
if [ -f "$OMI_DIR/var/run/omiserver.pid" ]; then
    pid=`cat $OMI_DIR/var/run/omiserver.pid`
   
    ps -aef | $AWK -v OFS=',' '{ print $2,$8 }' | grep "^$pid" | grep "omiserver" 1> /dev/null
    if [ $? -eq 0 ]; then
 OMI_IS_RUNNING=1
    fi
fi

# This will extract the CM logging path for scxcm.log, which can be set on install time to be something user specified.
# It reads in the scxcm.conf file in the CM installation's etc directory, and greps for PATH, which will be the path of any log file.
# A user may configure multiple log paths for different logging levels, but we only take the first log path in this implementation.
CM_LOGPATHS=`cat ../etc/scxcm.conf | grep PATH`
i=0
for temp in $CM_LOGPATHS; do
   if [ $i -eq 1 ]; then
       CM_LOGDIR=`dirname $temp`
       break
   fi
   i=`expr $i + 1`
done

if [ -z "$CM_LOGDIR" ]; then
    echo "ERROR: Unable to determine CM's logging directory"
    exit 1
fi

PLATFORM=`uname -s`
case $PLATFORM in
    Linux)
        ZIP="gz"
        COMPRESS="gzip"
        ;;
    HP-UX)
        ZIP="Z"
        COMPRESS="compress -f"
        ;;
    AIX)
        ZIP="Z"
        COMPRESS="compress -f"
        ;;
    SunOS)
        ZIP="Z"
        COMPRESS="compress -f"
        ;;
    *)
        echo "Unknown platform"
        exit 1
        ;;
esac

wait_for_omi_to_stop()
{
    if [ -f "$OMI_DIR/var/run/omiserver.pid" ]; then
 pid=`cat $OMI_DIR/var/run/omiserver.pid`
 
 if [ -z "$pid" ]; then
            echo "Cannot get pid for omiserver process; process may still exist.  Please manually restart omiserver."
 else
            # wait for it to exit
            stop=0
            count=5
    
            while [ $stop -eq 0 ]; do
  count=`expr $count - 1`
  
                # Check to see if omiserver is still running.
  ps -aef | $AWK -v OFS=',' '{ print $2,$8 }' | grep "^$pid" | grep "omiserver" 1> /dev/null
  if [ $? -ne 0 ]; then
                    stop=1
  elif [ $count -eq 0 ]; then
                    stop=1
                    if [ $? -eq 0 ]; then # pid matches commandline..
   echo "OMI Server process did not exit properly, forcing it to exit."
   kill -9 "$pid"
                    fi
  else
                    echo "Waiting for omiserver to exit..."
                    sleep 1
  fi
            done
 fi
    fi
}

service_action_delay()
{
    COUNT=0
    while [ $COUNT -lt 15 ]; do
        /usr/bin/svcs -H $1 2> /dev/null | grep -i $2 2> /dev/null 1> /dev/null
        [ $? -eq 0 ] && break
        echo "Waiting for service: $1 ..."
        sleep 2
        COUNT=`expr $COUNT + 1`
    done
}

pre_omi_and_ccmexec()
{
if [ $OMI_IS_RUNNING -eq 1 ]; then
    case $PLATFORM in
        Linux|HP-UX|AIX)
  ../../omi/bin/omiserver -s
   wait_for_omi_to_stop
            ;;
        SunOS)
     version=`uname -r`
     if [ "$version" = "5.9" ]; then
  if [ $CCM_IS_RUNNING -eq 1 ]; then
      ./ccmexec --openlogfile
  fi
  ../../omi/bin/omiserver -s
  wait_for_omi_to_stop
     else
  if [ $CCM_IS_RUNNING -eq 1 ]; then
      svcadm disable -s svc:/application/management/ccmexecd 2> /dev/null
  fi
  svcadm disable -s svc:/application/management/omiserver 2> /dev/null
  # wait for omiserver to stop (ccmexecd will enter disabled mode first because of the dependency)
                service_action_delay svc:/application/management/omiserverd disabled
     fi
            ;;
    esac
fi
}

post_omi_and_ccmexec()
{
if [ $OMI_IS_RUNNING -eq 1 ]; then
    case $PLATFORM in
        Linux|HP-UX|AIX)
     ../../omi/bin/omiserver -d 2> /dev/null 1> /dev/null
     if [ $CCM_IS_RUNNING -eq 1 ]; then
  ./ccmexec --openlogfile
     fi
            ;;
        SunOS)
     version=`uname -r`
     if [ "$version" = "5.9" ]; then
  ../../omi/bin/omiserver -d 2> /dev/null 1> /dev/null
  if [ $CCM_IS_RUNNING -eq 1 ]; then
          ./ccmexec --openlogfile
  fi
     else
  svcadm enable -s svc:/application/management/omiserver 2> /dev/null
  if [ $CCM_IS_RUNNING -eq 1 ]; then
      svcadm enable -s svc:/application/management/ccmexecd 2> /dev/null
  fi
     fi
            ;;
    esac
fi
}

usage()
{
    echo "Usage:"
    echo "    logrotate NUMBER_OF_LOGS_TO_KEEP"
    echo " where NUMBER_OF_LOGS_TO_KEEP is a postive integer"
    exit 1
}

if [ -z "$1" ]; then
    usage
fi

logs_to_keep=$1

if [ $logs_to_keep -le 0 ]; then
    usage
fi

 

# expects $1 - log path
# expects $2 - log name
rotate_log()
{
    LOGPATH=$1
    LOG_NAME=$2
   
    log_archives=`ls -t $LOGPATH/$LOG_NAME.* 2> /dev/null`
   
    # move the sorted list $log_archives into $1, $2, $3, etc..
    set -- split $log_archives
    shift
   
    num_files_found=$#
   
    out_path=
   
    if [ $logs_to_keep -gt $num_files_found ]; then
        # find lowest number that doesn't exist from 1 to $logs_to_keep
        i=1
        while [ $i -le $logs_to_keep ]; do
            value=`ls $LOGPATH/$LOG_NAME.$i.$ZIP 2> /dev/null`
            if [ $? -ne 0 ]; then
                out_path="$LOGPATH/$LOG_NAME.$i.$ZIP"
                break
            fi
            i=`expr $i + 1`
        done
    else
        if [ $logs_to_keep -lt $num_files_found ]; then
            # Note: should likely use a full path here to ensure nothing bad happens.
            num_logs_to_delete=`expr $num_files_found - $logs_to_keep`
     last_good_log_name=
            i=1
            for log in $log_archives; do
                if [ $i -gt $logs_to_keep ]; then
                    rm $log
  else
      last_good_log_name=$log
                fi
                i=`expr $i + 1`
            done
 else
     for log in $log_archives; do
  last_good_log_name=$log
     done
        fi
 out_path=$last_good_log_name
    fi

    out_path=`echo $out_path | sed "s/.$ZIP//"`
    echo "Rotating log to $out_path.$ZIP"

    if [ ! -f "$LOGPATH/$LOG_NAME" ]; then
 touch $LOGPATH/$LOG_NAME
    fi
    mv $LOGPATH/$LOG_NAME $out_path
    rm -f $out_path.$ZIP
    $COMPRESS $out_path
    touch $LOGPATH/$LOG_NAME
}

# stop ccmexec
pre_omi_and_ccmexec

rotate_log $CM_LOGDIR scxcm.log
rotate_log $OMI_LOGDIR omiserver.log
rotate_log $OMI_LOGDIR omiagent.root.root.log

# start ccmexec
post_omi_and_ccmexec