案例十九、分析Tomcat日誌

如果你們公司服務器上跑的是java的代碼,那多半會使用Tomcat,而Tomcat出現問題,我們就不得不去查看Tomcat日誌。Tomcat有一個總日誌叫catalina out,它記錄了Tomcat相關的信息,包括正確的和錯誤的。該案例的需求背景是:

服務器上跑着4個Tomcat實例,目錄結構如下:

/opt/TOMCAT/
├── crontabs
├── t1
├── t2
├── t3
└── t4

而catalina out所在路徑如下:

/opt/TOMCAT/t1/logs/catalina.out
/opt/TOMCAT/t2/logs/catalina.out
/opt/TOMCAT/t3/logs/catalina.out
/opt/TOMCAT/t4/logs/catalina.out

具體需求如下:

1)腳本可以取Tomcat實例t1-t4的日誌,通過參數指定是哪一個。

2)腳本可以自定義取日誌的起始位置,比如取今天早上10點之後到現在的日誌,要求提供的時間爲24小時制。

3)腳本可以自定義取日誌的起始和結束位置,比如取今天早上9點到20點的日誌,要求提供的時間爲24小時制。

4)第一個參數爲哪一個Tomcat(t1、t2、t3、t4),第二個參數爲起始時間點(只考慮當天的時間),第三個參數爲結束時間點,可以省略,如果省略則爲當前時間點。

5)提供的時間點需要判斷合法性,即必須爲12:00:00這種格式。


日誌片段如下:

Aug 22,2019 15:58:33 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["http-bio-8080"]
Aug 22,2019 16:38:23 PM org.apahce.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["ajp-bio-8009"]
Aug 22,2019 16:45:46 PM org.apahce.catalina.startup.Catalina start
INFO: Server startup in 2102 ms



知識點一:Tomcat介紹和安裝

Tomcat是一個web容器,我們主要用它來運行servlet和JSP。Tomcat本身也是一個http服務器,它可以像Apache或者Nginx那樣解析HTML網頁、JS、CSS以及圖片等元素,但它最主要的功能是用來運行Servlet或JSP。關於Tomcat涉及到一些JAVA相關的概念,下面簡單做一個羅列。

JAVAEE  Java Plateform Enterprise Edition   企業版本,用來做網站的
JAVASE  Java Plateform Standard Edition   標準版本,用來做電腦上運行的軟件的
JAVAME  Java Plateform Micro Edition      微型版本,做手機軟件的
JDK    Java Development kit       Java的開發和運行環境,JDK=Java開發工具+JRE
JRE    Java Runtime Environment   Java程序的運行環境,包括Java運行所需要的類庫和JVM
JVM    Java虛擬機
jar  (Java application archive)包含class和一些資源和配置文件的壓縮包
war  (web application archive)與jar基本相同,會包含全部的web應用程序,Tomcat會自動將其部署

上面提到了Servlet和JSP,它們二者的區別主要有以下幾點:

1)在html代碼中內嵌Java代碼就是jsp,而servlet是純Java代碼寫的。

2)jsp主要用來展現頁面效果,而servlet主要負責邏輯控制。

3)用戶第一次運行jsp時,會自動轉換爲servlet代碼,所以說jsp本質上就是一種servlet。

4)第一次訪問servlet時,會將其編譯爲類文件,後續可以直接訪問類文件。


關於Tomcat的安裝,這裏簡單列一下步驟,供參考:

1.安裝jdk(以下方法二選一)

方法一:yum安裝java-1.8.0-openjdk

# yum install -y java-1.8.0-openjdk

方法二:安裝Oracle官方版jdk

1)到https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 下載jdk8

2)解壓並改名/usr/local/jdk1.8

3)編輯配置文件/etc/profile,增加如下內容到最後:

JAVA_HOME=/usr/local/jdk1.8/
JAVA_BIN=/usr/local/jdk1.8/bin
JRE_HOME=/usr/local/jdk1.8/jre
PATH=$PATH:/usr/local/jdk1.8/bin:/usr/local/jdk1.8/jre/bin
CLASSPATH=/usr/local/jdk1.8/jre/lib:/usr/local/jdk1.8/lib:/usr/local/jdk1.8/jre/lib/charsets.jar


2.安裝Tomcat(版本爲9.0)

1)下載二進制包,下載地址爲https://tomcat.apache.org/download-90.cgi

2)解壓並改名/usr/local/tomcat

3)啓動/usr/local/tomcat/bin/startup.sh


知識點二:Tomcat單擊多實例

單擊多實例,就是在一臺服務器上跑多個Tomcat服務。其實想要運行Tomcat,不僅需要Tomcat的主程序文件(比如/usr/local/tomcat/bin下的二進制文件),還需要配置文件等輔助類文件。要想跑多個Tomcat服務,可以只需要一份主程序文件即可,不同的Tomcat服務使用不同的配置文件即可。所以,要想實現單擊多實例,可以這樣規劃一下目錄,如圖:

111.png

其中CATALINA_HOME指的是Tomcat安裝目錄(如果你按照我的方法安裝,那麼就是在/usr/local/tomcat),CATALINA_BASE爲實例所在目錄。CATALINA_HOME路徑下只需要包含bin和lib目錄,而CATALINA_BASE只存放conf、webapps、logs等這些文件,這樣部署的好處在於升級方便,配置及安裝文件間互不影響,在不影響Tomcat實例的前提下,替換掉CATALINA_HOME中的安裝文件。


具體的部署步驟如下:

1.創建實例目錄

# mkdir -p /data/tomcat-instance
# mkdir /data/tomcat-instance/www.123.com
# cd !$
# cp -r /usr/local/tomcat/conf /data/tomcat-instance/www.123.com/

2.創建Tomcat服務相關目錄

# mkdir -p /data/tomcat-instance/www.123.com/{common,logs,temp,server,shared,webapps,work}

3.創建啓動和關閉腳本

# cd /data/tomcat-instance/www.123.com
# vim start.sh  //啓動腳本
#!/bin/bash
export CATALINA_HOME=/usr/local/tomcat
export CATALINA_BASE=/data/tomcat-instance/www.123.com
TOMCAT_ID=`ps aux |grep "java"|grep "Dcatalina.base=$CATALINA_BASE "|grep -v "grep"|awk '{ print $2 }'`
if [ -n "$TOMCAT_ID" ]
then
    echo "tomcat(${TOMCAT_ID}) still running now , please shutdown it first";
    exit 2;
else
       $CATALINA_HOME/bin/startup.sh
    if [ "$?" = "0" ]; then
        echo "start succeed"
    else
        echo "start failed"
    fi
fi

# vim shutdown.sh  //關閉腳本
#!/bin/bash
export CATALINA_HOME=/usr/local/tomcat
export CATALINA_BASE=/data/tomcat-instance/www.123.com
TOMCAT_ID=`ps aux |grep "java"|grep "Dcatalina.base=$CATALINA_BASE "|grep -v "grep"|awk '{ print $2}'`
if [ -n "$TOMCAT_ID" ] ; then
    TOMCAT_STOP_LOG=`$CATALINA_HOME/bin/shutdown.sh`
       if [ "$?" = "0" ]; then
        echo "stop succeed"
    else
        echo "stop failed"
    fi
else
    echo "Tomcat instance not found"
    exit
fi

4.編輯配置文件

# cd /data/tomcat-instance/www.123.com/conf
# vim server.xml  //修改三個端口,目的是爲了不和其他實例衝突

有了第一個實例後,第二個實例可以直接複製/data/tomcat-instance/www.123.com目錄,然後修改對應的配置、啓動腳本、停止腳本內容。


知識點三:shell腳本的參數個數

在前面的案例中多次用到$1,$2,即shell腳本的參數。和參數相關的還有一個常用的概念,那就是shell腳本參數的個數。先看示例腳本:

# vim pa_nu.sh
#!/bin/bash
echo "腳本有$#個參數"

執行腳本,過程如下:

# sh pa_nu.sh 1 a
腳本有2個參數
# sh pa_nu.sh 
腳本有0個參數
# sh pa_nu.sh a b c
腳本有3個參數

所以,結論就是在shell腳本中用$#表示腳本的參數個數。


知識點四:判斷一個時間是否合法

如果使用傳統的方法,去比對時、分、秒的範圍是可以做到,但是這樣太繁瑣,有一個簡單的方法,如下:

# date -d "19:60:" +%s
date: 無效的日期"19:60:"
# date -d "19:59" +%s
1566561540

就是用date命令來做。


知識點五:將24小時制的時間轉換爲12小時制

直接看命令,如下:

# date -d "17:13:14" +%r
05:13:14 PM

也可以直接判斷一個時間是AM還是PM

# date -d "17:13:14" +%p   //小寫字母p
PM

如果想用小寫的,也可以做到:

# date -d "9:10:33" +%P  //大寫字母P
am


知識點六:比較兩個時間大小

比較時間大小,只能通過時間戳來實現,如下:

# t1=`date -d "13:22:32" +%s`
# t2=`date -d "15:00:00" +%s`
# if [ $t1 -lt $t2 ]; then echo "t1比t2要早"; else echo "t1比t2要晚"; fi
t1比t2要早
# if [ $t1 -lt $t2 ]; then echo "t1比t2要早"; else echo "t1比t2要晚"; fi
t1比t2要晚


本案例參考腳本

#!/bin/bash
#截取指定Tomcat的日誌片段
#作者:
#日期:

LANG=en
logfile="/opt/TOM/$1/logs/catalina.out"

#將當天的英文月、數字日期、數字年作爲變量賦值給d_mdy
d_mdy=`date "+%b %d, %Y"`

#判斷參數個數
if [ $# -ne 2 ] && [ $# -ne 3 ]
then
    echo "你提供的參數個數不對,請提供2個或者3個參數。例:sh $0 t1 08:01:00 14:00:00" 
    exit 1
fi

#判斷第一個參數是否符合要求
if ! echo $1|grep -qE '^t1$|^t2$|^t3$|^t4$'
then
    echo "第一個參數必須是t1、t2、t3或t4"
    exit 1
fi

#判斷時間有效性
judge_time()
{
    date -d "$1" +%s &>/dev/null
    if [ $? -ne 0 ]
    then
        echo "你提供的時間$1格式不正確"
        exit 1
    fi
}

#判斷提供的時間點是否在日誌中出現
judge_time_in_log()
{
    if ! grep -q "$d_mdy $(tr_24_12 $1)" $logfile
        then
            echo "你提供的時間$1在日誌$logfile中不曾出現,請換一個時間點"
            exit 1
        fi
}

#將24小時制時間轉換爲12小時
tr_24_12()
{
    date -d "$1" +%r
}

#判斷第2個參數是否合法
judge_time $2

#判斷起始時間點是否出現在日誌裏
judge_time_in_log $2

#如果提供第3個參數
if [ $# -eq 3 ]
then
    #判斷第3個參數是否合法
    judge_time $3

    #判斷起始時間是否早於結束時間
    t1=`date -d "$2" +%s`
        t2=`date -d "$3" +%s`
        if [ $t2 -lt $t1 ]
        then
            echo "你提供的時間$2比$3要晚,應該把早的時間放到前面"
            exit
        fi

        #判斷提供的結束時間點是否出現在日誌中
        judge_time_in_log $3
fi


#取起始時間所在行行號
begin_n=`grep -n "$d_mdy $(tr_24_12 $2)" $logfile|head -1|awk -F ':' '{print $1}'`

#取結束時間所在行行號,並用sed截取日誌內容
if [ $# -eq 3 ]
then
    n=`grep -n "$d_mdy $(tr_24_12 $3)" $logfile|tail -1|awk -F ':' '{print $1}'`
    #結束日期所在行的下一行纔是日誌的內容
    end_n=$[$n+1]
    sed -n "$begin_n,$end_n"p $logfile
else
    sed -n "$begin_n,$"p $logfile
fi


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章