使用 sqlplus 轮询并将结果记录到文件强制换行

Polling with sqlplus and logging result to a file forces in lineshifts

我正在尝试制作一个我认为是简单的 bash-脚本,该脚本定期轮询远程数据库并将以下元素记录到日志文件中,其中只有最后两个元素是来自 sql-query:

的行元素
Readable timestamp, timestamp, string, Request Duration

示例结果应如下所示:

Mon Sep 5 13:28:30 CEST 2016,1473074940127,text content, 4
Mon Sep 5 13:28:40 CEST 2016,1473074940127,text content, 3
Mon Sep 5 13:28:50 CEST 2016,1473074940127,text content, 2

此脚本的目的是主动监视和记录从我们的本地环境到远程数据库的响应时间,以便我们可以在测试时对应本地应用程序中的错误,以及最终的数据库连接问题或类似问题。出于这个原因,我们希望脚本也输出任何最终的错误消息。这些格式并不重要,但我们希望看到标准输出是 "comfortable" 一行。

我为此编写了以下非常简单的脚本,但它有一些怪癖,无论我如何调整它似乎都无法消除:

sleep_duration=10
while true; do

SECONDS=0
timestamp="$(date),"
echo -n $timestamp >> $LOG_PATH


sqlplus -s $database << EOF >> $LOG_PATH
    whenever sqlerror exit sql.sqlcode

    set echo off
    set heading off
    set linesize 1000
    set pagesize 0
    set numformat 9999999999999
    set colsep ,
    set null null

    SELECT COLUMN1, COLUMN2 FROM TABLE1;
    exit;
EOF

echo ', '$SECONDS >> $LOG_PATH

sleep $sleep_duration
done

我们向数据库发送的查询总是returns恰好一行有两个元素,并且这两个元素(INTEGER,VARCHAR2)总是具有相同的固定宽度。如果我们的应用程序在本地出现问题,它们都可以为 null。

我知道 SPOOL 和 TIMING 命令的存在,但已经测试并选择不使用这两个命令。假脱机查询不会向日志文件输出任何最终的意外错误,至少不会在错误终端输出的情况下进行欺骗,所以我首先使用了管道解决方案。看起来更简单。在数据库停机的情况下,TIMING 似乎无法正确显示查询的运行时间,因此我采用了 SECONDS 方法。我知道就包含的所有 sqlplus 开销而言,这并不精确,但无论如何我们对精确指标不感兴趣,我们通常只是想知道该过程是否需要不到一秒,或几分钟。毫秒基本上是无关紧要的。

然而,这有一个大问题,因为日志最终看起来像这样:

Mon Sep 5 14:50:47 CEST 2016, 1473079873483,text output

, 0
Mon Sep 5 14:50:57 CEST 2016, 1473079883483,text output

, 0
Mon Sep 5 14:51:07 CEST 2016, 1473079893489,text output

, 0

我希望 set pagesize 0 从结果中删除所有这样的尾随换行,但不管怎样,每次查询后似乎都有两个换行,无论如何我似乎都无法摆脱它我试试假脱机查询给出相同的结果。

我考虑过在 sqlplus-session 中循环,但由于脚本必须或多或少永久地 运行,我担心这会永久保留一个连接槽出于其他功能上无意义的目的,这是不可取的。根据需要打开和关闭它似乎更明智。我根本没有测试过这种方法,主要是因为这个原因。

我希望避免对日志进行 post 处理,因为我不知道其中可能会弹出什么样的错误条目,所以稍后对其进行美化感觉就像一个不必要的正则表达式-噩梦。

对于如何使输出干净利落地排在一行上,没有不必要的换行和空格,同时确保不会丢失任何最终错误,有没有人有任何建议?

这有点变通,因为它实际上并没有解决我仍然无法解释的换行问题,但是一个非常简单的解决方案是直接存储 sqlplus 输出到 bash 变量,而不是尝试直接从 sqlplus 打印到日志,并将其作为任何其他变量回显。

基本上,我必须在上面的脚本中进行更改,将 sqlplus 命令包装在变量 QUERY_OUTPUT=$() 中并删除输出的管道:

while true; do

SECONDS=0
timestamp=$(date) 
echo -n "$timestamp, " >> $LOG_PATH

QUERY_RESULT=$(sqlplus -s $database << EOF
    whenever sqlerror exit sql.sqlcode

    set echo off
    set heading off
    set linesize 1000
    set pagesize 0
    set numformat 9999999999999
    set colsep ', '
    set null null

    SELECT TIME, BROKER_NAME FROM ACTIVEMQ_LOCK;
    exit;
EOF
)

echo $QUERY_RESULT, $SECONDS seconds elapsed >> $LOG_PATH

sleep $sleep_duration
done

我自己偶然发现了这个解决方案,同时花了几个小时试图记录和验证我首先在上述问题中尝试过和未尝试过的内容,经过一些测试后它似乎工作得很好。一切都干净、可控地打印在一行上,任何最终的错误似乎也干净地打印在这一行上。找到我要找的东西。

自从我找到解决方案后,考虑只是一开始就没有问这个问题,但我认为其他人也可能会从中看到一些价值,至少我没能找到任何明显的重复。不妨分享一下!