Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 16865] ファイルの概要

このコミットは、Go言語の標準ライブラリ log/syslog パッケージにおける serverConn インターフェースの利用を復元するものです。以前のコミットで削除されたこのインターフェースは、特にSolaris上のgccgo環境において、syslogデーモンへの接続方法の特殊性に対応するために必要とされていました。

コミット

commit 0738c7e977b3ac190d6176555b69c8e9d2fb4de6
Author: Ian Lance Taylor <iant@golang.org>
Date:   Wed Jul 24 10:28:57 2013 -0700

    log/syslog: restore use of serverConn interface
    
    Revision 15629 (8d71734a0cb0) removed the serverConn interface
    that was introduce in revision 7718 (ee5e80c62862).  The
    serverConn interface was there for use by gccgo on Solaris,
    and it is still needed there.  Solaris does not support
    connecting to the syslog daemon over TCP, and gccgo simply
    calls the C library function.  This CL restores the
    interface.
    
    R=golang-dev, bradfitz, rsc
    CC=golang-dev
    https://golang.org/cl/11737043

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/0738c7e977b3ac190d6176555b69c8e9d2fb4de6

元コミット内容

log/syslog: restore use of serverConn interface

このコミットは、log/syslog パッケージにおいて serverConn インターフェースの使用を復元することを目的としています。以前のコミット (リビジョン 15629, ハッシュ 8d71734a0cb0) で削除されたこのインターフェースは、元々リビジョン 7718 (ハッシュ ee5e80c62862) で導入されたものでした。このインターフェースは、Solaris上でgccgoを使用する際に必要とされており、SolarisがTCP経由でのsyslogデーモンへの接続をサポートしていないため、gccgoがCライブラリ関数を直接呼び出す必要があるという特殊な状況に対応するためのものでした。この変更は、そのインターフェースを再度導入するものです。

変更の背景

Go言語の log/syslog パッケージは、システムログサービスへのメッセージ送信を抽象化します。しかし、異なるオペレーティングシステムやコンパイラ環境では、syslogデーモンとの通信方法に差異が生じることがあります。

このコミットの背景には、以下の経緯があります。

  1. serverConn インターフェースの導入 (リビジョン 7718, ee5e80c62862): 初期の段階で、特定の環境(特にSolaris上のgccgo)でのsyslog通信の特殊性を吸収するために serverConn インターフェースが導入されました。これは、Goの標準的な net.Conn インターフェースでは対応できない、Cライブラリの直接呼び出しが必要なケースを扱うためと考えられます。

  2. serverConn インターフェースの削除 (リビジョン 15629, 8d71734a0cb0): 何らかの理由(おそらく、コードの簡素化や、特定の環境への依存を減らす目的)で、この serverConn インターフェースが削除されました。しかし、この削除はSolaris上のgccgo環境におけるsyslog機能に影響を与えました。

  3. 問題の再発と serverConn の復元: serverConn インターフェースの削除後、Solaris上のgccgo環境でsyslogが正しく機能しないという問題が再発しました。SolarisはTCP経由でのsyslogデーモンへの接続をサポートしておらず、gccgoはCライブラリのsyslog関数を直接呼び出す必要があったため、このインターフェースが不可欠であることが判明しました。このコミットは、この問題を解決するために serverConn インターフェースを復元し、Solaris環境での互換性を確保することを目的としています。

前提知識の解説

syslog

syslogは、UNIX系オペレーティングシステムでシステムログメッセージを生成、保存、管理するための標準的なプロトコルです。アプリケーションやシステムプロセスは、syslogプロトコルを使用してイベントメッセージをsyslogデーモンに送信し、デーモンはこれらのメッセージをファイル、コンソール、またはリモートのsyslogサーバーに書き込みます。

Go言語の log/syslog パッケージ

Go言語の標準ライブラリには、syslogプロトコルを介してシステムログにメッセージを書き込むための log/syslog パッケージが含まれています。このパッケージは、Dial 関数を通じてsyslogデーモンへの接続を確立し、Writer 型を通じてメッセージを送信する機能を提供します。

net.Conn インターフェース

Go言語の net パッケージには、ネットワーク接続を表す net.Conn インターフェースが定義されています。これは、ReadWriteClose などの基本的なネットワーク操作を提供し、TCPやUDPなどの様々なネットワークプロトコルに共通のインターフェースを提供します。

gccgo

gccgoは、GCC (GNU Compiler Collection) のフロントエンドとして実装されたGo言語のコンパイラです。Go言語の公式コンパイラであるgcとは異なり、gccgoはGCCのバックエンドを利用するため、様々なアーキテクチャやオペレーティングシステムへの移植が容易です。しかし、その実装の違いから、特定のシステムコールやライブラリの扱いに差異が生じることがあります。

Solarisにおけるsyslog接続の特殊性

一般的なLinuxシステムなどでは、syslogデーモンへの接続はUnixドメインソケット(/dev/log/var/run/syslog など)やUDP/TCPポート(通常は514番)を介して行われます。しかし、Solarisでは、TCP経由でのsyslogデーモンへの直接接続がサポートされていない場合があります。代わりに、C標準ライブラリの syslog(3) 関数を呼び出すことが推奨されるか、あるいはそれが唯一の手段となることがあります。gccgoのようなコンパイラは、このようなプラットフォーム固有の制約に対応するために、Cライブラリの関数を直接呼び出すメカニズムを必要とします。

技術的詳細

このコミットの核心は、Goのインターフェースの柔軟性を利用して、プラットフォーム固有のsyslog通信メカニズムを抽象化することにあります。

serverConn インターフェースの定義

type serverConn interface {
	writeString(p Priority, hostname, tag, s, nl string) error
	close() error
}

このインターフェースは、syslogメッセージを書き込むための writeString メソッドと、接続を閉じるための close メソッドを定義しています。これにより、具体的な接続の実装(例: net.Conn を使用したネットワーク接続、またはCライブラリ呼び出し)を抽象化できます。

netConn 構造体の導入と serverConn インターフェースの実装

type netConn struct {
	conn net.Conn
}

func (n netConn) writeString(p Priority, hostname, tag, msg, nl string) error {
	timestamp := time.Now().Format(time.RFC3339)
	_, err := fmt.Fprintf(n.conn, "<%d>%s %s %s[%d]: %s%s",
		p, timestamp, hostname,
		tag, os.Getpid(), msg, nl)
	return err
}

func (n netConn) close() error {
	return n.conn.Close()
}

netConn 構造体は、内部に標準の net.Conn を保持し、この netConnserverConn インターフェースを実装します。これにより、通常のネットワーク接続を介したsyslog通信が serverConn インターフェースを通じて行えるようになります。writeString メソッドでは、syslogメッセージのフォーマット(RFC3339タイムスタンプ、ホスト名、タグ、PIDなどを含む)を行い、内部の net.Conn に書き込んでいます。

Writer 構造体の変更

type Writer struct {
	// ...
	mu   sync.Mutex // guards conn
	conn serverConn // Changed from net.Conn to serverConn
}

Writer 構造体の conn フィールドの型が net.Conn から serverConn インターフェースに変更されました。これにより、WriterserverConn インターフェースを満たす任意の型(netConn や、Solaris上のgccgoが提供するカスタム実装など)を扱うことができるようになります。

connect() メソッドの変更

func (w *Writer) connect() (err error) {
	// ...
	if w.conn != nil {
		w.conn.close() // Call close() method of serverConn interface
		w.conn = nil
	}

	// ...
	if err == nil {
		w.conn = netConn{c} // Wrap net.Conn with netConn to satisfy serverConn
		// ...
	}
	// ...
}

connect() メソッド内で、既存の接続を閉じる際に w.conn.Close() ではなく w.conn.close() が呼び出されるようになりました。これは、connserverConn インターフェース型になったためです。 また、net.Dial で取得した net.Conn オブジェクトを w.conn に代入する際に、netConn{c} のように netConn 構造体でラップするようになりました。これにより、net.ConnserverConn インターフェースを満たすようになります。

Close() メソッドの変更

func (w *Writer) Close() error {
	// ...
	if w.conn != nil {
		err := w.conn.close() // Call close() method of serverConn interface
		w.conn = nil
		return err
	}
	// ...
}

Close() メソッドでも同様に、w.conn.Close() ではなく w.conn.close() が呼び出されるようになりました。

write() メソッドの変更

func (w *Writer) write(p Priority, msg string) (int, error) {
	// ...
	err := w.conn.writeString(p, w.hostname, w.tag, msg, nl) // Call writeString() method
	if err != nil {
		return 0, err
	}
	// ...
}

write() メソッドでは、直接 fmt.Fprintf を使用して w.conn に書き込む代わりに、w.conn.writeString() メソッドを呼び出すようになりました。これにより、実際の書き込みロジックが serverConn インターフェースの実装に委譲されます。

syslog_unix.go の変更

func unixSyslog() (conn serverConn, err error) { // Return type changed to serverConn
	// ...
	if err == nil {
		return netConn{conn}, nil // Wrap net.Conn with netConn
	}
	// ...
}

syslog_unix.go ファイルの unixSyslog 関数の戻り値の型が net.Conn から serverConn に変更されました。これにより、Unixドメインソケット経由で接続が確立された場合も、その接続が netConn でラップされて serverConn インターフェースとして返されるようになります。

Solaris固有の実装(想定)

このコミットメッセージによると、Solaris上のgccgoは syslog_solaris.go というファイルで unixSyslog を実装し、serverConn インターフェースを満たす型を返すことで、Cライブラリのsyslog関数を呼び出すと説明されています。このコミットは、そのSolaris固有の実装が機能するために必要な serverConn インターフェースを復元するものです。

コアとなるコードの変更箇所

src/pkg/log/syslog/syslog.go

  • Writer 構造体の conn フィールドの型が net.Conn から serverConn インターフェースに変更。
  • serverConn インターフェースが定義された。
  • netConn 構造体が定義され、serverConn インターフェースを実装。
  • Writer.connect() メソッド内で、w.conn.Close()w.conn.close() に、w.conn = cw.conn = netConn{c} に変更。
  • Writer.Close() メソッド内で、w.conn.Close()w.conn.close() に変更。
  • Writer.write() メソッド内で、fmt.Fprintf による直接書き込みが w.conn.writeString() の呼び出しに変更。

src/pkg/log/syslog/syslog_unix.go

  • unixSyslog() 関数の戻り値の型が net.Conn から serverConn に変更。
  • net.Dial で取得した net.ConnnetConn{conn} でラップして返すように変更。

コアとなるコードの解説

このコミットの主要な目的は、Goの log/syslog パッケージが、標準的なネットワーク接続だけでなく、Solaris上のgccgoのようにCライブラリを直接呼び出す必要がある特殊な環境でも動作するようにすることです。

  1. インターフェースによる抽象化: serverConn インターフェースを導入することで、syslogメッセージの書き込みと接続のクローズという共通の操作を抽象化しています。これにより、Writer 型は具体的な接続の実装(TCP/UDPソケット、Unixドメインソケット、またはCライブラリ呼び出し)に依存せず、serverConn インターフェースを満たす任意のオブジェクトを扱うことができます。

  2. netConn による標準実装のラップ: netConn 構造体は、Goの標準的な net.Conn をラップし、serverConn インターフェースを実装します。これにより、既存のネットワークベースのsyslog通信は、この新しいインターフェースを通じて透過的に機能し続けます。

  3. Writer の汎用化: Writer 構造体の conn フィールドが serverConn インターフェース型になったことで、Writer はより汎用的なsyslogクライアントとして機能します。connect() メソッドで接続を確立する際、通常のネットワーク接続であれば netConn でラップされたオブジェクトが conn に設定され、Solarisのような特殊な環境では、その環境固有の serverConn 実装が設定されることになります。

  4. 書き込みロジックの委譲: write() メソッドが w.conn.writeString() を呼び出すようになったことで、実際のメッセージフォーマットと書き込み処理は serverConn インターフェースの実装に委譲されます。これにより、各実装は自身の最適な方法でsyslogメッセージを送信できます。例えば、netConnfmt.Fprintf を使ってソケットに書き込み、Solarisのカスタム実装はCライブラリの syslog(3) 関数を呼び出す、といった具合です。

この変更により、log/syslog パッケージは、異なるプラットフォームやコンパイラ環境におけるsyslog通信の差異を吸収し、より堅牢で移植性の高いコードベースとなりました。

関連リンク

参考にした情報源リンク

  • Go言語の公式リポジトリ (GitHub): https://github.com/golang/go
  • Go言語のコードレビューシステム (Gerrit): https://go.dev/cl/ (コミットメッセージに記載されている https://golang.org/cl/11737043 はGerritの変更リストへのリンクです)
  • syslogプロトコルに関するRFC (例: RFC 5424)
  • Go言語のインターフェースに関する公式ドキュメントやチュートリアル
  • Solarisのシステムプログラミングに関するドキュメント (一般的な情報源)
  • GCCGoの内部実装に関する情報 (一般的な情報源)
  • Go言語のコミット履歴 (GitHubまたはGerrit)
  • Go言語のIssueトラッカー (問題報告や議論の履歴)
  • Go言語のメーリングリスト (golang-devなど)