开发者

How to log error queries in mysql?

开发者 https://www.devze.com 2022-12-27 10:56 出处:网络
I know that there is general_log that logs all queries, but I want to find out which query has an error, and get the er开发者_开发百科ror message. I have tried running an error query on purpose, but i

I know that there is general_log that logs all queries, but I want to find out which query has an error, and get the er开发者_开发百科ror message. I have tried running an error query on purpose, but it logs as a normal query and doesn't report it with error. Any ideas?


There is no functionality in MySQL to do this.

You will have to stick with application-layer logging.


I know this is ancient now, but for anyone having the same issue that lands here from Google, here's my two cents.

If you're using the cli client, you can simply redirect your sterr to a file, and then parse through that.

mysql -u user -p 2> errors.log


It is possible to log error queries with the MariaDB Audit Plugin.

The MariaDB Audit Plugin works for MariaDB, MySQL and Percona Server.

For example, for these queries

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

log seems like this:

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

Last column is return code. 0 is Ok. Else - error.


Even though this question is quite old I hope it will be useful to someone who searched for mysql log error queries or similar terms.

Not too long ago I also required mysqld to log only erroneous queries. I found that mysql-proxy enables you to do that and wrote a small LUA script:

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 needed for logging table, adjust somedb.mysql_error to liking, but don't forget to do so in the above LUA script also.

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

To use the script, run

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

or if that fails (>=v0.9)

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

The proxy runs on port 4040 by default, to test:

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

and run some faulty sql.

When everything seems to be in order set the port in your application to 4040 instead of the actual mysqld port and you have mysql error logging on the database level.

Final note: mysql-proxy is beta. Use with caution I guess. Been running here for almost half a year now without problems, however YMMV.


I have tried running an error query on purpose, but it logs as a normal query and doesn't report it with error. Any ideas?

so, you did it wrong. No other idea without the code.

in PHP I'm doing it this way (assume you're using mysql driver):

$res=mysql_query($sql) or trigger_error(mysql_error().$sql);

it will log all erroneous queries if you have log_errors setting on (and you have to)

EDIT: I see now, you want global level logging,m not application level. But may be application level will suit you as well?


MariaDB is capable to do this with a plugin https://mariadb.com/kb/en/sql-error-log-plugin/ which is distributed with mariadb.

I tried this yesterday and it works as advertised.

One need to just run:

install plugin SQL_ERROR_LOG soname 'sql_errlog';

and the queries with errors will go to $datadir/sql_errors.log that is on most linux install at /var/lib/mysql/sql_errors.log.

0

精彩评论

暂无评论...
验证码 换一张
取 消