如何在MySQL中记录错误查询?

9

我知道有一个general_log记录所有查询,但是我想找出哪个查询有错误,并获取错误消息。我已经故意运行了一个错误查询,但它被记录为正常查询,并没有报告错误。有什么想法吗?

6个回答

7

1
为什么?一个问题 - 为什么?难道这很难做吗?只需在将其返回给客户端时记录查询和错误即可。 - Serge Velikan
@Serge:我不知道。看起来应该不难实现。也许这是一种关注点分离的方法(即客户端有责任正确获取SQL语句,并且可以自由地记录失败)。 - Lightness Races in Orbit

4

我知道这已经很陈旧了,但是对于任何通过Google来到这里的人遇到相同问题的人,这是我的两分钱建议。

如果您正在使用cli客户端,您可以将sterr重定向到文件中,然后解析该文件。

mysql -u user -p 2> errors.log

谢谢,我不知道可以这样做,而不是记录到文件中。我改成记录到数据库里了。干杯。 - Van Nguyen

4

使用MariaDB审计插件可以记录错误查询。

MariaDB审计插件适用于MariaDB、MySQL和Percona Server。

例如,对于这些查询

select now();
select now()+();
select 9+();
select 'hello';

日志看起来像这样:

20150807 23:00:36,mnv-Satellite-L300D,root,localhost,82,377,QUERY,`test`,'select now()
LIMIT 0, 1000',0
20150807 23:00:37,mnv-Satellite-L300D,root,localhost,82,379,QUERY,`test`,'select now()+()',1064
20150807 23:00:37,mnv-Satellite-L300D,root,localhost,82,382,QUERY,`test`,'select 9+()',1064
20150807 23:00:38,mnv-Satellite-L300D,root,localhost,82,383,QUERY,`test`,'select \'hello\'
LIMIT 0, 1000',0

最后一栏是返回码,0表示操作成功,否则表示出现错误。


1
我提供一个下载链接:https://downloads.mariadb.com/Audit-Plugin/MariaDB-Audit-Plugin/ - lutaoact
那个下载链接 https://downloads.mariadb.com/Audit-Plugin/MariaDB-Audit-Plugin/ 似乎失效了。 - SomeoneElse
1
这是我去年得到的最好的钻石!! - Alex

2

虽然这个问题很老,但我希望这对于那些搜索mysql日志错误查询或类似术语的人有用。

不久前,我也需要将mysqld仅记录错误查询。我发现mysql-proxy可以实现这一点,并编写了一个小的LUA脚本:

local err_flag = false
function read_query( packet )
    if packet:byte() == proxy.COM_QUERY then
        local user = proxy.connection.client.username
        local host = proxy.connection.client.src.name
        if user:lower() == 'someuser' then -- change this to any condition where errors should be logged
            proxy.queries:append(1, packet, {resultset_is_needed = true})
            proxy.queries:append(2, string.char(proxy.COM_QUERY) .. "SET @last_query = '" .. string.sub(packet, 2) .. "'", {resultset_is_needed = true} )
            proxy.queries:append(3, string.char(proxy.COM_QUERY) .. "SHOW WARNINGS", {resultset_is_needed = true} )
        end
        return proxy.PROXY_SEND_QUERY
    end
end


function insert_query(err_t, err_n, err_m)
  local query = "INSERT INTO `somedb`.`mysql_error` " .. -- change log destination 
    "(`date`, `err_num`,`err_type`, `err_message`, `problem_query`, `conn_id`)" ..
    " VALUES ( NOW(), " ..
    err_n  ..  "," .. "\"" ..
    err_t .."\"" .. "," .. "\"" ..
    err_m .. "\"" .. "," ..
    "@last_query" .. "," ..
    proxy.connection.server.thread_id .. ")"
    proxy.queries:append(4, string.char(proxy.COM_QUERY) .. query, {resultset_is_needed = true})
    return proxy.PROXY_SEND_QUERY
end


function read_query_result(inj)
    local res = assert(inj.resultset)
    if inj.id == 1 then
        err_flag = false
        if res.query_status == proxy.MYSQLD_PACKET_ERR then
            err_flag = true
            return proxy.PROXY_IGNORE_RESULT
        end
    elseif inj.id == 2 then
        return proxy.PROXY_IGNORE_RESULT
    elseif inj.id == 3 then
        if err_flag == true then
            for row in res.rows do
                proxy.response.type = proxy.MYSQLD_PACKET_ERR
                proxy.response.errmsg = row[3]
                insert_query(row[1], row[2], row[3])
            end
            return proxy.PROXY_SEND_RESULT
        end
        return proxy.PROXY_IGNORE_RESULT
    elseif inj.id == 4 then
        return proxy.PROXY_IGNORE_RESULT
    end
end

需要为日志表生成DDL,调整somedb.mysql_error至所需,但不要忘记在上面的LUA脚本中也这样做。

CREATE TABLE `somedb`.`mysql_error` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `date` datetime NOT NULL,
    `err_num` smallint(6) NOT NULL,
    `err_type` varchar(10) COLLATE utf8_unicode_ci NOT NULL,
    `err_message` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
    `problem_query` varchar(8000) COLLATE utf8_unicode_ci NOT NULL,
    `conn_id` int(11) NOT NULL,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

要使用脚本,请运行:

/path/to/mysql-proxy --proxy-lua-script=/path/to/mysql-proxy-log-error-queries.lua

如果失败(>=v0.9):

/path/to/mysql-proxy --proxy-lua-script=/path/to/mysql-proxy-log-error-queries.lua --plugins=proxy

代理默认在端口4040上运行,进行测试:

mysql -u username -p --host=127.0.0.1 --port=4040

并运行一些有错误的SQL。

当所有事情看起来都很正常时,将应用程序中的端口设置为4040而不是实际的mysqld端口,然后您就可以在数据库级别上记录mysql错误。

最后注意:mysql-proxy处于beta版本。请谨慎使用。我已经在这里运行了将近半年的时间,没有问题,但你的情况可能不同。


不错,我试了一下,花了一些时间才最终让它正常工作,但效果非常好。顺便说一句,这还不是测试版,仍然是α版。http://dev.mysql.com/downloads/mysql-proxy/ - Van Nguyen
这不是性能杀手吗?我认为在客户端进行错误处理就可以了。 - Zaffy
很高兴听到这个! :) - kon

1
我曾经故意运行了一个错误查询,但它被记录为正常查询,并没有报告错误。有什么想法吗?
所以,你做错了。没有代码的话,没有其他想法。
在PHP中,我是这样做的(假设您正在使用mysql驱动程序):
$res=mysql_query($sql) or trigger_error(mysql_error().$sql);

如果您开启了log_errors设置(并且必须这样做),它将记录所有错误查询。

编辑: 我现在明白了,您想要全局级别的日志记录,而不是应用程序级别的。 但是应用程序级别也可能适合您?


我通过 phpmyadmin 3.3.2 输入了 SQL,这样做有问题吗? - Van Nguyen
@user phpMyAdmin是单用户应用程序,因此不需要任何登录。 - Your Common Sense
trigger_error函数会将错误信息写入到PHP的错误日志中,而不是MySQL的日志。如果您的shell脚本也使用了MySQL,那么可能需要查看MySQL的错误日志来获取相关信息。 - Van Nguyen
@user 这是 PHP 指令。它会写入标准的 PHP 错误日志。 - Your Common Sense
谢谢您的回答,但这并没有解决我的问题,因为它是依赖于PHP的。 - Van Nguyen

0

MariaDB可以通过一个插件https://mariadb.com/kb/en/sql-error-log-plugin/来实现这一点,该插件随MariaDB一起分发。

我昨天尝试了一下,它的效果与广告宣传的一样。

只需要运行以下命令即可:

install plugin SQL_ERROR_LOG soname 'sql_errlog';

有错误的查询将被记录在 $datadir/sql_errors.log 中,该文件通常位于大多数Linux安装中的 /var/lib/mysql/sql_errors.log


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接