7
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

golangci-lintのforbidigoを使って、標準出力でエラーで出している箇所を検出できるようにした話

7
Last updated at Posted at 2025-12-03

:santa: はじめに

この記事は、スタンバイ Advent Calendar 2025の記事として書いています。

昨年も参加して、記事を書いていたのですが、あっという間の1年でした:sweat_smile:

さて、本記事ではサービス運用における失敗談と、その対策についてお話しします。
商用環境で意図しないエラー出力を行っていたため検知が遅れてしまった経験から、同じミスを防ぐための golangci-lint の活用方法を紹介します。

:no_good: この記事で話さないこと :no_good:

  • golangci-lintのインストール方法
  • golangci-lintの詳しい設定方法

概要

商用で稼働しているGoによるAPIが意図しないエラー出力方法をしており、エラー発見が遅れてしまうという事態が発生してしまいました :disappointed_relieved:

具体的には下記コードのように、 errnil でなければ err を出力する処理です。
本来はログレベルを「Error」にして出力すべきところを、誤って fmt.Println で標準出力してしまっていました。
専用のロギングメソッドを用意していたにも関わらず、コードレビューをすり抜けてしまいました。

package main

import (
	"errors"
	"fmt"
)

func main() {
	// 何かしらの処理
	err := errors.New("error!!!!")

	if err != nil {
		fmt.Println(err)
	}
}

レビュー時に気づき修正できればいいのですが、人の目によるレビューも限界があります。
最近では、AIによるレビューも発展しているので、AIによる指摘でも問題はないかもしれません。
ただ、今回のような問題であれば静的解析でやるほうがコスト面や速度面で優れていると思っているので、今回は golangci-lint を使い検知できるようにしてみました。

:information_source: golangci-lintのforbidigoについて

今回使用したのは、 golangci-lint で使える、 forbidigo です。
これは、特定の記述を禁止することができるリンターです。
デフォルトでは、 ^(fmt\.Print.*|print|println)$ が禁止文字列として設定されています。

詳しくは、READMEをご参照ください。

:rocket: サンプルコードによる検出

説明するよりも実際に動かして見たほうがわかりやすいと思うので、試しに動かしてみましょう!

とりあえず、必要なディレクトリと初期化を行います。

mkdir forbidigo && cd forbidigo && go mod init test-forbidigo

main.go に今回の検出したい、 fmt.Println があるファイルを用意します。

fmt2 は、あとで使うため、一旦はスルーしてください!

cat <<EOF > main.go
package main

import (
	"errors"
	"fmt"
	fmt2 "fmt"
)

func main() {
	// 何かしらの処理
	err := errors.New("error!!!!")

	if err != nil {
		fmt.Println(err)
		fmt2.Println(err)
	}
}
EOF

実際に golangci-lint で検出できるかテストしてみましょう!

golangci-lint run --enable-only=forbidigo .
main.go:14:3: use of `fmt.Println` forbidden by pattern `^(fmt\.Print(|f|ln)|print|println)$` (forbidigo)
                fmt.Println(err)
                ^
1 issues:
* forbidigo: 1

実際に検出ができていそうです!
ただ、 forbidigo をそのまま使うと fmt2.Println のほうが検知できません。
これは、 README にも記載されていますが、型情報を活用した検知をするためには、 analyze_types を有効にする必要があります。

今回は、 fmt パッケージなのでそれを別名で扱うことは少ないかと思いますが、他のパッケージの記述を検出したい場合に必要かと思い参考事例としてあげています。

forbidigoanalyze_types を有効にするため設定ファイルが必要なので、設定ファイルを用意してみましょう。

This needs to be enabled through the analyze_types command line parameter. Beware this may have a performance impact because additional information is required for the analysis.

READMEに上記の記載があり、analyze_types の有効化は、分析する内容が増えるためパフォーマンスに影響がある可能性があるため、使う際には注意してください。

cat <<EOF > .golangci.yml
# See the dedicated "version" documentation section.
version: "2"
linters:
  default: none
  enable:
    - forbidigo
  settings:
    forbidigo:
      analyze-types: true
EOF

試しに実行してみると、今度は fmt2.Println も検出できるようになりました!
これで、別名を付けられているパッケージにも検出ができるようになりました。

golangci-lint run .
main.go:14:3: use of `fmt.Println` forbidden by pattern `^(fmt\.Print(|f|ln)|print|println)$` (forbidigo)
                fmt.Println(err)
                ^
main.go:15:3: use of `fmt2.Println` forbidden by pattern `^(fmt\.Print(|f|ln)|print|println)$` (forbidigo)
                fmt2.Println(err)
                ^
2 issues:
* forbidigo: 2

まとめ

  • golangci-lintforbidigo を使えば条件にマッチする記述を検出することができる
  • パッケージに別名を付けている場合は、 analyze-types を true にする必要がある

明日は、@shohei-nishimoto の さんの 「キーボード作ってますか?Vol.2」 の記事となります!ぜひ、楽しみにしていてください!

7
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?