Gopls: デーモンとして実行

注:この機能は新しいものです。バグに遭遇した場合は、issue を提出してください。

すぐに試したい場合は、クイックスタートにスキップしてください。

背景:gopls の実行モード

Gopls は元々 LSP サイドカーとして実装されました。これはエディターまたはエディタープラグインによって起動され、stdin/stdout を介して jsonrpc 2.0 を使用して通信するプロセスです。ステートフルプロセスとして実行することで、gopls は大量のキャッシュを維持し、編集中のソースコードに対して積極的に解析を実行できます。

この実行モードは、多くの独立したエディタープロセスがある場合や、エディタープロセスが短命な場合にはうまく機能しません。これは Vim や Emacs のような非 IDE エディターのユーザーにはよくあることです。多くのプロセスがあるということは、多くのキャッシュがあるということであり、かなりのシステムリソースを消費します。短命なセッションを使用すると、セッションが作成されるたびに起動コストを支払うことになります。

これらのワークフロータイプをサポートするために、gopls 実行の新しいモードがサポートされています。このモードでは、単一の永続的で共有された gopls 「デーモン」プロセスがすべての gopls セッションの管理を担当します。このモードでは、エディターは引き続き gopls サイドカーを起動しますが、このサイドカーは LSP を共有 gopls インスタンスに転送し、メトリクス、ログ、および rpc トレースを記録するだけの薄い「フォワーダー」として機能します。

クイックスタート

共有 gopls インスタンスを使用するには、デーモンプロセスを自分で管理するか、gopls フォワーダープロセスが必要に応じて共有デーモンを起動させる必要があります。

-remote=auto で実行する

デーモンの自動管理が最も簡単で、エディターによって起動される gopls プロセスに -remote=auto フラグを渡すことで行うことができます。これにより、このプロセスは必要に応じて gopls デーモンを自動起動し、それに接続して LSP を転送します。たとえば、以下は、より簡単なデバッグのために追加のフラグを設定する、合理的な gopls 呼び出しの例です。

gopls -remote=auto -logfile=auto -debug=:0 -remote.debug=:0 -rpc.trace

共有 gopls プロセスは、接続されているクライアントがない状態で1分後に自動的にシャットダウンすることに注意してください。

デーモンを手動で管理する

フォワーダーに管理させるのではなく、外部手段で gopls デーモンプロセスを管理するには、-listen=<addr> フラグを使用して gopls デーモンプロセスを起動し、次にエディターによって起動される gopls プロセスに -remote=<addr> を渡す必要があります。

たとえば、TCP ポート 37374 でデーモンをホストするには、以下のようにします。

gopls -listen=:37374 -logfile=auto -debug=:0

そして、エディターから以下を実行します。

gopls -remote=:37374 -logfile=auto -debug=:0 -rpc.trace

POSIX システムを使用している場合は、フラグの値の前に unix; を付けることで、Unix ドメインソケットを使用することもできます。たとえば、

gopls -listen="unix;/tmp/gopls-daemon-socket" -logfile=auto -debug=:0

そして、以下を介して接続します。

gopls -remote="unix;/tmp/gopls-daemon-socket" -logfile=auto -debug=:0 -rpc.trace

(これらのフラグ値は、';' が特別なシェル文字であるため、引用符で囲む必要があることに注意してください。このため、この構文は将来変更される可能性があります。)

デバッグ

共有 gopls セッションのデバッグは、LSP の処理に関与する gopls プロセスが2つあるため、シングルトンセッションよりも複雑です。いくつかヒントを以下に示します。

ログファイルとデバッグアドレスの検索

デーモンモードで実行している場合、gopls inspect sessions コマンドを使用して、gopls デーモンインスタンス(および接続されているすべてのクライアント)のログファイルとデバッグポートを見つけることができます。デフォルトでは、これはデフォルトのデーモン(つまり -remote=auto)を検査します。別のデーモンを検査するには、-remote フラグを明示的に使用します:gopls -remote=localhost:12345 inspect sessions

これは -remote.debug を有効にしているかどうかに関わらず機能します。

デバッグページの移動

-debug=:0 が gopls に渡されると、ステートフルなデバッグページを提供するウェブサーバーが実行されます(troubleshooting.mdを参照)。これらのページをホストしている実際のポートは、gopls inspect sessions コマンドを使用するか、ログファイルの先頭を確認することで見つけることができます。これは最初のログメッセージの1つになります。たとえば、-logfile=auto を使用している場合、head /tmp/gopls-<pid>.log を確認することでデバッグアドレスを見つけます。

デフォルトでは、gopls デーモンは -debug で開始されません。これを有効にするには、フォワーダーインスタンスで -remote.debug フラグを設定し、デーモンを起動する際に -debug を付けて gopls を呼び出すようにします。

フォワーダープロセスのデバッグページには、デーモンサーバープロセスのデバッグページへのリンクがあります。同様に、デーモンプロセスのデバッグページには、各クライアントへのリンクがあります。

これにより、さまざまなサーバーやクライアントのメトリクス、トレース、ログファイルを見つけるのに役立ちます。

ログファイルの使用

gopls デーモンは、デフォルトでロギングが無効になって起動します。これをカスタマイズするには、-remote.logfile を gopls フォワーダーに渡します。-remote.logfile=auto を使用すると、デーモンはデフォルトの場所(POSIX システムの場合:/tmp/gopls-daemon-<pid>.log)にログを記録します。

gopls デーモンはセッションスコープのメッセージをログに記録しません。これらはフォワーダーに反映され、エディターからアクセスできるようになります。デーモンログには、セッションの接続および切断時のログなど、グローバルメッセージのみが含まれます。

フォワーダー gopls プロセスを -rpc.trace で開始することをお勧めします。これにより、そのログファイルに LSP セッションに固有の rpc トレースログが含まれます。

複数の共有 gopls インスタンスの使用

複数の共有 gopls インスタンスを持つことが望ましい環境があるかもしれません。デーモンを手動で管理する場合、これは各デーモンプロセスで異なる -listen アドレスを選択するだけで行うことができます。

POSIX システムでは、異なる共有 gopls プロセスの自動管理もサポートされています。異なるデーモンは -remote="auto;<id>" を渡すことで選択できます。<id> に同じ値を渡す gopls フォワーダーはすべて同じ共有デーモンを使用します。

FAQ

Q: 共有 gopls を使用しているのに、期待したほどメモリが節約されないのはなぜですか?

A: implementation.md に記載されているように、gopls にはビュー/セッション/キャッシュの概念があります。各セッションとビューは、厳密に1つのエディターセッションにマップされます(編集されたが未保存のバッファなどを含むため)。キャッシュには、任意のエディターセッションから独立したものが含まれており、したがって共有できます。

たとえば、3つのエディターセッションが1つの gopls プロセスを共有している場合、キャッシュは共有されますが、それぞれが独自のセッションとビューを持ちます。このモードでのメモリ節約は、3つの独立した gopls プロセスと比較して、セッション間のキャッシュの重複量に相当します。

これまであまり重要視されていなかったため、セッション/ビューからキャッシュに移動できる状態があり、それによって共有モードでのメモリ節約量が増える可能性があります。

Q: -remote=auto を使用している場合、デーモンインスタンスをカスタマイズするにはどうすればよいですか?

デーモンは、フォワーダー gopls の -remote.* 形式のフラグを使用してカスタマイズできます。これにより、フォワーダーはデーモンを起動する際にこれらの設定で gopls を呼び出します。執筆時点では、以下の設定を公開しています。

  • -remote.logfile: デーモンのログファイルの場所
  • -remote.debug: デーモンのデバッグアドレス
  • -remote.listen.timeout: 現在接続がない状態で、デーモンが新しい接続を待つ時間。シャットダウンする前に、有効な time.Duration(例:30s5m)に設定する必要があります。0 の場合、無期限にリッスンします。デフォルト:1m

デーモンが既に実行されている場合、これらのフラグを設定してもその設定は変更されません。これらのフラグは、実際にデーモンを起動するフォワーダープロセスにのみ関係します。


このドキュメントのソースファイルは、golang.org/x/tools/gopls/doc の下にあります。