docker安装tomcat下的日志查看

描述

在本地运行的项目测试通过。可是部署到linux服务器后,发现测试出现些问题。服务器环境是使用docker安装的tomcat。

进行

一般来说,出现问题,排查日志能解决大部分情况。可是docker进入运行中的tomcat,发现logs目录下并没有网上说的/usr/local/tocmat/logs/catalina.out文件。在进入到l/usr/local/tocmat/logs目录下,发现其文件结构如下。
catalina.2020-04-03.log host-manager.2020-04-03.log localhost_access_log.2020-04-03.txt
localhost.2020-04-03.log manager.2020-04-03.log。

为了再确认下,在tomcat安装目录下使用了如下命令找了找,发现还是没。

find . -name "*catalina*"

这个文件比较关键,因为里面记录了java程序的控制台输出和异常信息。对于此在网上找了很多解决方案,最后一个说法非常适用。参考文章地址在文末。

原因

首先,打开/usr/local/bin/catalina.sh文件,看其中关键的部分如下。

从图中可以看到,当使用/usr/local/tocmat/catalina.sh run的时候,其实是不会创建/usr/local/tocmat.logs/catalina.out文件的,因为这个文件只有在catalina.sh start的时候才会创建。而docker的初始执行命令就是sh /usr/local/tocmat/bin/catalina.sh run。因此需要覆盖这个初始命令。
在这里插入图片描述
catalina.sh部分如下。

elif [ "$1" = "start" ] ; then

  if [ ! -z "$CATALINA_PID" ]; then
    if [ -f "$CATALINA_PID" ]; then
      if [ -s "$CATALINA_PID" ]; then
        echo "Existing PID file found during start."
        if [ -r "$CATALINA_PID" ]; then
          PID=`cat "$CATALINA_PID"`
          ps -p $PID >/dev/null 2>&1
          if [ $? -eq 0 ] ; then
            echo "Tomcat appears to still be running with PID $PID. Start aborted."
            echo "If the following process is not a Tomcat process, remove the PID file and try again:"
            ps -f -p $PID
            exit 1
          else
            echo "Removing/clearing stale PID file."
            rm -f "$CATALINA_PID" >/dev/null 2>&1
            if [ $? != 0 ]; then
              if [ -w "$CATALINA_PID" ]; then
                cat /dev/null > "$CATALINA_PID"
              else
                echo "Unable to remove or clear stale PID file. Start aborted."
                exit 1
              fi
            fi
          fi
        else
          echo "Unable to read PID file. Start aborted."
          exit 1
        fi
      else
        rm -f "$CATALINA_PID" >/dev/null 2>&1
        if [ $? != 0 ]; then
          if [ ! -w "$CATALINA_PID" ]; then
            echo "Unable to remove or write to empty PID file. Start aborted."
            exit 1
          fi
        fi
      fi
    fi
  fi

  shift
  touch "$CATALINA_OUT"
  if [ "$1" = "-security" ] ; then
    if [ $have_tty -eq 1 ]; then
      echo "Using Security Manager"
    fi
    shift
    eval $_NOHUP "\"$_RUNJAVA\"" "\"$LOGGING_CONFIG\"" $LOGGING_MANAGER "$JAVA_OPTS" "$CATALINA_OPTS" \
      -D$ENDORSED_PROP="\"$JAVA_ENDORSED_DIRS\"" \
      -classpath "\"$CLASSPATH\"" \
      -Djava.security.manager \
      -Djava.security.policy=="\"$CATALINA_BASE/conf/catalina.policy\"" \
      -Dcatalina.base="\"$CATALINA_BASE\"" \
      -Dcatalina.home="\"$CATALINA_HOME\"" \
      -Djava.io.tmpdir="\"$CATALINA_TMPDIR\"" \
      org.apache.catalina.startup.Bootstrap "$@" start \
      >> "$CATALINA_OUT" 2>&1 "&"

  else
    eval $_NOHUP "\"$_RUNJAVA\"" "\"$LOGGING_CONFIG\"" $LOGGING_MANAGER "$JAVA_OPTS" "$CATALINA_OPTS" \
      -D$ENDORSED_PROP="\"$JAVA_ENDORSED_DIRS\"" \
      -classpath "\"$CLASSPATH\"" \
      -Dcatalina.base="\"$CATALINA_BASE\"" \
      -Dcatalina.home="\"$CATALINA_HOME\"" \
      -Djava.io.tmpdir="\"$CATALINA_TMPDIR\"" \
      org.apache.catalina.startup.Bootstrap "$@" start \
      >> "$CATALINA_OUT" 2>&1 "&"

  fi

  if [ ! -z "$CATALINA_PID" ]; then
    echo $! > "$CATALINA_PID"
  fi

  echo "Tomcat started."

对于新的覆盖命令。有两种解决方案,一种/usr/local/tocmat/bin/catalina.sh start这个命令,可是这个执行后,一会tomcat就停止了(去掉59行和69行最后的"&", 参考文章见文末)。另外一种,是将/usr/local/tocmat/bin/catalina.sh run的输出重定向到/usr/local/tocmat/bin/logs/catalina.out中。 我们采用第二种方式。该方式的命令如下。

/usr/local/tomcat/bin/catalina.sh run >> /usr/local/tomcat/logs/catalina.out 2>&

将这个命令作为一个脚本, 名称为/usr/local/tocmat/bin/start.sh 挂载到docker容器中,然后用sh /usr/local/tocmat/bin/start.sh覆盖初始命令。
最终的docker启动tomcat容器命令如下。

docker run --name tomcat -p 8080:8080 -v ~/docker/mount/tomcat/webapps:/usr/local/tomcat/webapps -v ~/docker/mount/tomcat/bin/start.sh:/usr/local/tomcat/bin/start.sh -d tomcat bash /usr/local/tomcat/bin/start.sh

扩展

使用上面方法,可以在/usr/local/tocmat/logs/目录下创建出catalina.out文件。通过日志排查,发现在windows上传文件的路径解析这个路径的文件名时候,发生异常。定位到当时上传文件的文件名为D:\temp\substrate.txt, 在linux上获取文件名的时候还是D:\temp\substrate.txt。

打开getName的源码如下。

public String getName() {
        int index = path.lastIndexOf(separatorChar);
        if (index < prefixLength) return path.substring(prefixLength);
        return path.substring(index + 1);
    }

如图所示,getName是和文件系统的分隔符(separatorChar)有关。对此我们做了下面测试。在同一个代码,分别在windows环境和linux环境进行测试。

String origin_file = "D:\\abc\\def\\k.txt";
System.out.println(new File(origin_file).getName());

上面代码在windows上输出是k.txt, 而在linux上输出却是D:\abc\def\k.txt。

解决

对于上面情况,一般需要编写可以跨平台的代码。其一是使用File.separator分隔符来代替具体的"\“或者”/"。其二对于windows系统来说,"\“或者”/”都可以,对于linux系统来说,只能使用"/",因此可以将路径全部写成"/"。

参考

https://www.cnblogs.com/barneywill/p/11013669.html
https://www.cnblogs.com/kangping/p/7150881.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值