Carpe Diem

備忘録

DockerでMySQLのクエリログを見れるようにする

背景

GraphQLでN+1になってないかを確認したいときに、スロークエリだけでなく全てのクエリログを見たくなったのでその設定方法を説明します。

  • Dockerコンテナの中に直接入って見る方法
  • Dockerログに吐き出す方法

の2通りで説明します。

環境

設定方法

まずは直接コンテナに入って見る方法です。

MySQLの設定

ローカルもしくはDockerコンテナ内でmysqlにログインして次のクエリを投げると設定を確認できます。

mysql> show variables like 'general_log%';
+------------------+---------------------------------+
| Variable_name    | Value                           |
+------------------+---------------------------------+
| general_log      | OFF                             |
| general_log_file | /var/lib/mysql/cfadc6a5faf3.log |
+------------------+---------------------------------+

general_logONになっていないとクエリログは出ないのでONにします。

mysql> set global general_log = on;

mysql> show variables like 'general_log%';
+------------------+---------------------------------+
| Variable_name    | Value                           |
+------------------+---------------------------------+
| general_log      | ON                              |
| general_log_file | /var/lib/mysql/cfadc6a5faf3.log |
+------------------+---------------------------------+

以上で設定はOKです。

確認

後はコンテナに入り、general_log_fileをtailすればクエリログを見ることができます。

$ tail -f /var/lib/mysql/cfadc6a5faf3.log

2023-11-30T01:21:20.370746Z        38 Connect   root@192.168.65.1 on mydb using TCP/IP
2023-11-30T01:21:20.371718Z        38 Query     SELECT @@socket, @@max_allowed_packet, @@wait_timeout
2023-11-30T01:21:20.374743Z        38 Prepare   SELECT `mydb`.`User`.`id`, `mydb`.`User`.`email`, `mydb`.`User`.`name` FROM `mydb`.`User` WHERE 1=1 ORDER BY `mydb`.`User`.`id` ASC LIMIT ? OFFSET ?
2023-11-30T01:21:20.375434Z        38 Execute   SELECT `mydb`.`User`.`id`, `mydb`.`User`.`email`, `mydb`.`User`.`name` FROM `mydb`.`User` WHERE 1=1 ORDER BY `mydb`.`User`.`id` ASC LIMIT 100 OFFSET 0
2023-11-30T01:21:20.376700Z        38 Prepare   SELECT `mydb`.`Post`.`id`, `mydb`.`Post`.`authorId` FROM `mydb`.`Post` WHERE `mydb`.`Post`.`authorId` IN (?)
2023-11-30T01:21:20.377051Z        38 Execute   SELECT `mydb`.`Post`.`id`, `mydb`.`Post`.`authorId` FROM `mydb`.`Post` WHERE `mydb`.`Post`.`authorId` IN (1)
2023-11-30T01:21:34.027736Z        14 Query     select * from User

ログファイルの場所を変更したい場合

デフォルトだとランダムな文字列のファイル名になっているので、固定したファイルに吐き出したい場合は次のように設定します。

mysql> set global general_log_file = '/tmp/mysql.log';

mysql> show variables like 'general_log%';
+------------------+----------------+
| Variable_name    | Value          |
+------------------+----------------+
| general_log      | ON             |
| general_log_file | /tmp/mysql.log |
+------------------+----------------+

Dockerログに直接吐き出す方法

次はdockerの標準出力ログに吐き出す方法です。

  • docker run
  • docker-compose

の2通りで解説します。

docker run

docker runにおけるCOMMANDを次のようにいじります。

$ docker run -p 3306:3306 \
  -e MYSQL_ROOT_PASSWORD="mypass" \
  mysql \
  bash -c 'touch /tmp/mysql.log && tail -f /tmp/mysql.log & /usr/local/bin/docker-entrypoint.sh mysqld --datadir=/var/lib/mysql --user=root --general-log=true --general-log-file=/tmp/mysql.log'

general-log-file/dev/stdoutが指定できたらシンプルにできて理想ですが、現在はエラーが出ます(以前はできたようです)。

docker-compose

docker-composeの場合は次のようなyamlになります。

version: "3.9"

services:
  mysql:
    image: arm64v8/mysql:8
    restart: always
    command: >
      bash -c '
      touch /tmp/mysql.log &&
      tail -f /tmp/mysql.log &
      /usr/local/bin/docker-entrypoint.sh mysqld
      --character-set-server=utf8mb4
      --collation-server=utf8mb4_unicode_ci
      --general-log=true
      --general-log-file=/tmp/mysql.log
      '
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: mypass
      MYSQL_DATABASE: mydb

その他

localhostでアクセスするとコケる

host名をlocalhostでアクセスしようとすると、

$ mysql --host=localhost  -u root -p

次のようにエラーになりました。

ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)

mysqllocalhostを利用した接続に際してはUNIXドメインソケットを使おうと試みるため、127.0.0.1としてTCPコネクションにする必要があるようです。

$ mysql --host=127.0.0.1  -u root -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 39
Server version: 8.2.0 MySQL Community Server - GPL

Copyright (c) 2000, 2023, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

参考