[インデックス 11722] ファイルの概要
このコミットは、Go言語の標準ライブラリである log/syslog
パッケージにおける、Writer
インターフェースの実装に関する修正です。具体的には、netConn
型の writeBytes
および writeString
メソッドが返す値が、実際にユーザーが提供したデータの長さを示すように変更されています。
コミット
commit 3fce00d99e30d66f63f8e3cb85debc137329db0d
Author: Rob Pike <r@golang.org>
Date: Thu Feb 9 08:36:13 2012 +1100
log/syslog: return length of data provided by the user, not length of header
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/5644059
---
src/pkg/log/syslog/syslog.go | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/src/pkg/log/syslog/syslog.go b/src/pkg/log/syslog/syslog.go
index aef63480f1..700b983c75 100644
--- a/src/pkg/log/syslog/syslog.go
+++ b/src/pkg/log/syslog/syslog.go
@@ -136,11 +136,19 @@ func (w *Writer) Debug(m string) (err error) {
}
func (n netConn) writeBytes(p Priority, prefix string, b []byte) (int, error) {
- return fmt.Fprintf(n.conn, "<%d>%s: %s\\n", p, prefix, b)
+ _, err := fmt.Fprintf(n.conn, "<%d>%s: %s\\n", p, prefix, b)
+ if err != nil {
+ return 0, err
+ }
+ return len(b), nil
}
func (n netConn) writeString(p Priority, prefix string, s string) (int, error) {
- return fmt.Fprintf(n.conn, "<%d>%s: %s\\n", p, prefix, s)
+ _, err := fmt.Fprintf(n.conn, "<%d>%s: %s\\n", p, prefix, s)
+ if err != nil {
+ return 0, err
+ }
+ return len(s), nil
}
func (n netConn) close() error {
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/3fce00d99e30d66f63f8e3cb85debc137329db0d
元コミット内容
log/syslog: return length of data provided by the user, not length of header
このコミットは、log/syslog
パッケージにおいて、ログメッセージを書き込む際に返されるバイト数が、Syslogヘッダーの長さではなく、ユーザーが提供した実際のメッセージデータの長さを返すように修正するものです。
変更の背景
Go言語の log/syslog
パッケージは、Syslogプロトコルを使用してログメッセージを送信するための機能を提供します。Syslogメッセージは通常、プライオリティ、タイムスタンプ、ホスト名、アプリケーション名などの情報を含むヘッダーと、実際のメッセージ本文(データ)で構成されます。
fmt.Fprintf
関数は、フォーマットされた文字列を io.Writer
に書き込み、書き込まれたバイト数とエラーを返します。以前の実装では、netConn.writeBytes
および netConn.writeString
メソッドが fmt.Fprintf
の戻り値をそのまま返していました。この戻り値には、Syslogヘッダー(プライオリティ、プレフィックス、コロン、スペースなど)とメッセージ本文の合計バイト数が含まれていました。
しかし、ログ書き込み関数(例えば io.Writer
インターフェースを実装する関数)の一般的な慣習として、書き込み関数が返すバイト数は、ユーザーが提供した入力データの長さであるべきです。これは、呼び出し元が実際にどれだけのデータが処理されたかを正確に把握し、必要に応じて残りのデータを処理したり、エラーハンドリングを行ったりするために重要です。
この不一致は、log/syslog
パッケージを使用するアプリケーションが、書き込み操作の成功を判断したり、送信されたデータの量を正確に追跡したりする際に混乱を招く可能性がありました。例えば、ユーザーが100バイトのメッセージを送信したにもかかわらず、関数が150バイトを返した場合、呼び出し元はSyslogプロトコルの詳細を知らない限り、その差分がどこから来たのか理解できません。
このコミットは、この慣習からの逸脱を修正し、より予測可能で直感的なAPI動作を提供することを目的としています。
前提知識の解説
Syslogプロトコル
Syslogは、システムログメッセージを収集するための標準プロトコルです。RFC 3164(旧)やRFC 5424(新)で定義されています。Syslogメッセージは通常、以下の要素で構成されます。
- PRI (Priority): メッセージのファシリティ(発生源)と重要度(Severity)を示す数値。
<PRI>
の形式でメッセージの先頭に付加されます。 - HEADER: タイムスタンプ、ホスト名、アプリケーション名、プロセスIDなど。
- MSG (Message): 実際のログメッセージ本文。
Syslogメッセージの一般的なフォーマットは <PRI>HEADER MSG
のようになります。このコミットで扱われているのは、特に fmt.Fprintf
が書き込む <%d>%s: %s\n
の部分で、これは PRI
と HEADER
の一部(プレフィックス)および MSG
を含んでいます。
Go言語の io.Writer
インターフェース
Go言語では、データを書き込むための汎用的なインターフェースとして io.Writer
が定義されています。
type Writer interface {
Write(p []byte) (n int, err error)
}
Write
メソッドは、p
からデータを書き込み、書き込まれたバイト数 n
とエラー err
を返します。この n
は、通常、p
の長さ(つまり、ユーザーが提供したデータの長さ)と一致することが期待されます。もし n < len(p)
であれば、それは部分的な書き込みを示し、呼び出し元は残りのデータを再試行するなどの処理を行う必要があります。
fmt.Fprintf
関数
fmt.Fprintf
は、Go言語の fmt
パッケージに含まれる関数で、指定された io.Writer
にフォーマットされた文字列を書き込みます。
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error)
この関数は、書き込まれたバイト数 n
とエラー err
を返します。ここで返される n
は、format
文字列と a
の値が展開された結果、実際に w
に書き込まれた全体のバイト数です。
技術的詳細
このコミットの核心は、fmt.Fprintf
の戻り値の解釈と、io.Writer
インターフェースの慣習との整合性です。
以前のコードでは、netConn.writeBytes
と netConn.writeString
は以下のように実装されていました。
func (n netConn) writeBytes(p Priority, prefix string, b []byte) (int, error) {
return fmt.Fprintf(n.conn, "<%d>%s: %s\\n", p, prefix, b)
}
func (n netConn) writeString(p Priority, prefix string, s string) (int, error) {
return fmt.Fprintf(n.conn, "<%d>%s: %s\\n", p, prefix, s)
}
ここで fmt.Fprintf
が返す int
値は、Syslogメッセージ全体の長さ(ヘッダー部分 + ユーザーデータ部分)でした。例えば、ユーザーが b
または s
として "Hello" という文字列(5バイト)を提供し、ヘッダー部分が20バイトだった場合、fmt.Fprintf
は25を返していました。
しかし、log/syslog
パッケージの Writer
インターフェースを実装するこれらのメソッドは、io.Writer
の Write
メソッドと同様に、ユーザーが提供したデータの長さ(この場合は len(b)
または len(s)
)を返すことが期待されます。
このコミットでは、この期待に応えるために、fmt.Fprintf
の戻り値のうち、書き込まれたバイト数 (n
) を破棄し、代わりにユーザーが提供したデータの長さ (len(b)
または len(s)
) を明示的に返すように変更しました。
// 変更前:
// return fmt.Fprintf(n.conn, "<%d>%s: %s\\n", p, prefix, b)
// 変更後:
_, err := fmt.Fprintf(n.conn, "<%d>%s: %s\\n", p, prefix, b) // 書き込まれたバイト数は破棄
if err != nil {
return 0, err // エラーがあれば0バイトとエラーを返す
}
return len(b), nil // エラーがなければユーザーデータの長さを返す
この変更により、log/syslog
パッケージの Writer
メソッドは、io.Writer
の一般的なセマンティクスに合致し、より予測可能で一貫性のある動作を提供するようになりました。
コアとなるコードの変更箇所
変更は src/pkg/log/syslog/syslog.go
ファイル内の netConn
型の以下の2つのメソッドに集中しています。
func (n netConn) writeBytes(p Priority, prefix string, b []byte) (int, error)
func (n netConn) writeString(p Priority, prefix string, s string) (int, error)
それぞれのメソッドで、fmt.Fprintf
の戻り値のうち、書き込まれたバイト数を受け取る変数を _
(ブランク識別子) に変更し、代わりに len(b)
または len(s)
を返すように修正されています。また、fmt.Fprintf
がエラーを返した場合のハンドリングも追加されています。
コアとなるコードの解説
writeBytes
メソッドの変更
func (n netConn) writeBytes(p Priority, prefix string, b []byte) (int, error) {
- return fmt.Fprintf(n.conn, "<%d>%s: %s\\n", p, prefix, b)
+ _, err := fmt.Fprintf(n.conn, "<%d>%s: %s\\n", p, prefix, b)
+ if err != nil {
+ return 0, err
+ }
+ return len(b), nil
}
- 変更前:
fmt.Fprintf
の戻り値(書き込まれたバイト数とエラー)をそのまま返していました。このバイト数にはSyslogヘッダーの長さが含まれていました。 - 変更後:
fmt.Fprintf
の戻り値のうち、書き込まれたバイト数は_
で破棄されます。err
変数でエラーを受け取ります。if err != nil
でエラーチェックを行い、エラーがあれば0
バイトとエラーを即座に返します。これは、書き込みが失敗した場合は0バイトが処理されたと見なす一般的なパターンです。- エラーがなければ、
len(b)
(ユーザーが提供したバイトスライスの長さ)を返します。これにより、呼び出し元は実際に送信を要求したデータの長さが返されたことを確認できます。
writeString
メソッドの変更
func (n netConn) writeString(p Priority, prefix string, s string) (int, error) {
- return fmt.Fprintf(n.conn, "<%d>%s: %s\\n", p, prefix, s)
+ _, err := fmt.Fprintf(n.conn, "<%d>%s: %s\\n", p, prefix, s)
+ if err != nil {
+ return 0, err
+ }
+ return len(s), nil
}
- この変更は
writeBytes
メソッドと全く同じロジックで、バイトスライスb
の代わりに文字列s
を扱っています。 len(s)
(ユーザーが提供した文字列の長さ)を返すことで、io.Writer
のセマンティクスに準拠しています。
これらの変更により、log/syslog
パッケージの Writer
インターフェースを介してログを書き込むアプリケーションは、より正確で期待通りの戻り値を受け取ることができるようになり、エラーハンドリングやログの追跡が容易になります。
関連リンク
- Go言語
log/syslog
パッケージのドキュメント: https://pkg.go.dev/log/syslog - Go言語
fmt
パッケージのドキュメント: https://pkg.go.dev/fmt - Go言語
io
パッケージのドキュメント: https://pkg.go.dev/io - RFC 5424 - The Syslog Protocol: https://datatracker.ietf.org/doc/html/rfc5424
参考にした情報源リンク
- Go言語の公式ドキュメント (pkg.go.dev)
- RFC 5424 (IETF)
- Go言語のコミット履歴とコードレビューシステム (golang.org/cl)
- 一般的なプログラミングにおける
write
関数の戻り値に関する慣習 fmt.Fprintf
の動作に関するGo言語のドキュメント- Syslogプロトコルに関する一般的な知識
- Go言語の
io.Writer
インターフェースのセマンティクスに関する知識 - Go言語の
_
(ブランク識別子) の使用法に関する知識 - Go言語のエラーハンドリングの慣習に関する知識
- GitHubのコミットページ: https://github.com/golang/go/commit/3fce00d99e30d66f63f8e3cb85debc137329db0d
- Go CL 5644059: https://golang.org/cl/5644059 (これは古いCLシステムへのリンクであり、現在はGerritに移行しているため、直接アクセスできない場合がありますが、コミットメッセージに記載されているため参照しました。)
# [インデックス 11722] ファイルの概要
このコミットは、Go言語の標準ライブラリである `log/syslog` パッケージにおける、`Writer` インターフェースの実装に関する修正です。具体的には、`netConn` 型の `writeBytes` および `writeString` メソッドが返す値が、実際にユーザーが提供したデータの長さを示すように変更されています。
## コミット
commit 3fce00d99e30d66f63f8e3cb85debc137329db0d Author: Rob Pike r@golang.org Date: Thu Feb 9 08:36:13 2012 +1100
log/syslog: return length of data provided by the user, not length of header
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/5644059
src/pkg/log/syslog/syslog.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)\n diff --git a/src/pkg/log/syslog/syslog.go b/src/pkg/log/syslog/syslog.go index aef63480f1..700b983c75 100644 --- a/src/pkg/log/syslog/syslog.go +++ b/src/pkg/log/syslog/syslog.go @@ -136,11 +136,19 @@ func (w *Writer) Debug(m string) (err error) { }
func (n netConn) writeBytes(p Priority, prefix string, b []byte) (int, error) {
- return fmt.Fprintf(n.conn, "<%d>%s: %s\n", p, prefix, b)
- _, err := fmt.Fprintf(n.conn, "<%d>%s: %s\n", p, prefix, b)
- if err != nil {
-
return 0, err
- }
- return len(b), nil }
func (n netConn) writeString(p Priority, prefix string, s string) (int, error) {
- return fmt.Fprintf(n.conn, "<%d>%s: %s\n", p, prefix, s)
- _, err := fmt.Fprintf(n.conn, "<%d>%s: %s\n", p, prefix, s)
- if err != nil {
-
return 0, err
- }
- return len(s), nil }
func (n netConn) close() error {
## GitHub上でのコミットページへのリンク
[https://github.com/golang/go/commit/3fce00d99e30d66f63f8e3cb85debc137329db0d](https://github.com/golang/go/commit/3fce00d99e30d66f63f8e3cb85debc137329db0d)
## 元コミット内容
`log/syslog: return length of data provided by the user, not length of header`
このコミットは、`log/syslog` パッケージにおいて、ログメッセージを書き込む際に返されるバイト数が、Syslogヘッダーの長さではなく、ユーザーが提供した実際のメッセージデータの長さを返すように修正するものです。
## 変更の背景
Go言語の `log/syslog` パッケージは、Syslogプロトコルを使用してログメッセージを送信するための機能を提供します。Syslogメッセージは通常、プライオリティ、タイムスタンプ、ホスト名、アプリケーション名などの情報を含むヘッダーと、実際のメッセージ本文(データ)で構成されます。
`fmt.Fprintf` 関数は、フォーマットされた文字列を `io.Writer` に書き込み、書き込まれたバイト数とエラーを返します。以前の実装では、`netConn.writeBytes` および `netConn.writeString` メソッドが `fmt.Fprintf` の戻り値をそのまま返していました。この戻り値には、Syslogヘッダー(プライオリティ、プレフィックス、コロン、スペースなど)とメッセージ本文の合計バイト数が含まれていました。
しかし、ログ書き込み関数(例えば `io.Writer` インターフェースを実装する関数)の一般的な慣習として、書き込み関数が返すバイト数は、ユーザーが提供した入力データの長さであるべきです。これは、呼び出し元が実際にどれだけのデータが処理されたかを正確に把握し、必要に応じて残りのデータを処理したり、エラーハンドリングを行ったりするために重要です。
この不一致は、`log/syslog` パッケージを使用するアプリケーションが、書き込み操作の成功を判断したり、送信されたデータの量を正確に追跡したりする際に混乱を招く可能性がありました。例えば、ユーザーが100バイトのメッセージを送信したにもかかわらず、関数が150バイトを返した場合、呼び出し元はSyslogプロトコルの詳細を知らない限り、その差分がどこから来たのか理解できません。
このコミットは、この慣習からの逸脱を修正し、より予測可能で直感的なAPI動作を提供することを目的としています。
## 前提知識の解説
### Syslogプロトコル
Syslogは、システムログメッセージを収集するための標準プロトコルです。RFC 3164(旧)やRFC 5424(新)で定義されています。Syslogメッセージは通常、以下の要素で構成されます。
* **PRI (Priority)**: メッセージのファシリティ(発生源)と重要度(Severity)を示す数値。`<PRI>` の形式でメッセージの先頭に付加されます。
* **HEADER**: タイムスタンプ、ホスト名、アプリケーション名、プロセスIDなど。
* **MSG (Message)**: 実際のログメッセージ本文。
Syslogメッセージの一般的なフォーマットは `<PRI>HEADER MSG` のようになります。このコミットで扱われているのは、特に `fmt.Fprintf` が書き込む `<%d>%s: %s\n` の部分で、これは `PRI` と `HEADER` の一部(プレフィックス)および `MSG` を含んでいます。
### Go言語の `io.Writer` インターフェース
Go言語では、データを書き込むための汎用的なインターフェースとして `io.Writer` が定義されています。
```go
type Writer interface {
Write(p []byte) (n int, err error)
}
Write
メソッドは、p
からデータを書き込み、書き込まれたバイト数 n
とエラー err
を返します。この n
は、通常、p
の長さ(つまり、ユーザーが提供したデータの長さ)と一致することが期待されます。もし n < len(p)
であれば、それは部分的な書き込みを示し、呼び出し元は残りのデータを再試行するなどの処理を行う必要があります。
fmt.Fprintf
関数
fmt.Fprintf
は、Go言語の fmt
パッケージに含まれる関数で、指定された io.Writer
にフォーマットされた文字列を書き込みます。
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error)
この関数は、書き込まれたバイト数 n
とエラー err
を返します。ここで返される n
は、format
文字列と a
の値が展開された結果、実際に w
に書き込まれた全体のバイト数です。
技術的詳細
このコミットの核心は、fmt.Fprintf
の戻り値の解釈と、io.Writer
インターフェースの慣習との整合性です。
以前のコードでは、netConn.writeBytes
と netConn.writeString
は以下のように実装されていました。
func (n netConn) writeBytes(p Priority, prefix string, b []byte) (int, error) {
return fmt.Fprintf(n.conn, "<%d>%s: %s\\n", p, prefix, b)
}
func (n netConn) writeString(p Priority, prefix string, s string) (int, error) {
return fmt.Fprintf(n.conn, "<%d>%s: %s\\n", p, prefix, s)
}
ここで fmt.Fprintf
が返す int
値は、Syslogメッセージ全体の長さ(ヘッダー部分 + ユーザーデータ部分)でした。例えば、ユーザーが b
または s
として "Hello" という文字列(5バイト)を提供し、ヘッダー部分が20バイトだった場合、fmt.Fprintf
は25を返していました。
しかし、log/syslog
パッケージの Writer
インターフェースを実装するこれらのメソッドは、io.Writer
の Write
メソッドと同様に、ユーザーが提供したデータの長さ(この場合は len(b)
または len(s)
)を返すことが期待されます。
このコミットでは、この期待に応えるために、fmt.Fprintf
の戻り値のうち、書き込まれたバイト数 (n
) を破棄し、代わりにユーザーが提供したデータの長さ (len(b)
または len(s)
) を明示的に返すように変更しました。
// 変更前:
// return fmt.Fprintf(n.conn, "<%d>%s: %s\\n", p, prefix, b)
// 変更後:
_, err := fmt.Fprintf(n.conn, "<%d>%s: %s\\n", p, prefix, b) // 書き込まれたバイト数は破棄
if err != nil {
return 0, err // エラーがあれば0バイトとエラーを返す
}
return len(b), nil // エラーがなければユーザーデータの長さを返す
この変更により、log/syslog
パッケージの Writer
メソッドは、io.Writer
の一般的なセマンティクスに合致し、より予測可能で一貫性のある動作を提供するようになりました。
コアとなるコードの変更箇所
変更は src/pkg/log/syslog/syslog.go
ファイル内の netConn
型の以下の2つのメソッドに集中しています。
func (n netConn) writeBytes(p Priority, prefix string, b []byte) (int, error)
func (n netConn) writeString(p Priority, prefix string, s string) (int, error)
それぞれのメソッドで、fmt.Fprintf
の戻り値のうち、書き込まれたバイト数を受け取る変数を _
(ブランク識別子) に変更し、代わりに len(b)
または len(s)
を返すように修正されています。また、fmt.Fprintf
がエラーを返した場合のハンドリングも追加されています。
コアとなるコードの解説
writeBytes
メソッドの変更
func (n netConn) writeBytes(p Priority, prefix string, b []byte) (int, error) {
- return fmt.Fprintf(n.conn, "<%d>%s: %s\\n", p, prefix, b)
+ _, err := fmt.Fprintf(n.conn, "<%d>%s: %s\\n", p, prefix, b)
+ if err != nil {
+ return 0, err
+ }
+ return len(b), nil
}
- 変更前:
fmt.Fprintf
の戻り値(書き込まれたバイト数とエラー)をそのまま返していました。このバイト数にはSyslogヘッダーの長さが含まれていました。 - 変更後:
fmt.Fprintf
の戻り値のうち、書き込まれたバイト数は_
で破棄されます。err
変数でエラーを受け取ります。if err != nil
でエラーチェックを行い、エラーがあれば0
バイトとエラーを即座に返します。これは、書き込みが失敗した場合は0バイトが処理されたと見なす一般的なパターンです。- エラーがなければ、
len(b)
(ユーザーが提供したバイトスライスの長さ)を返します。これにより、呼び出し元は実際に送信を要求したデータの長さが返されたことを確認できます。
writeString
メソッドの変更
func (n netConn) writeString(p Priority, prefix string, s string) (int, error) {
- return fmt.Fprintf(n.conn, "<%d>%s: %s\\n", p, prefix, s)
+ _, err := fmt.Fprintf(n.conn, "<%d>%s: %s\\n", p, prefix, s)
+ if err != nil {
+ return 0, err
+ }
+ return len(s), nil
}
- この変更は
writeBytes
メソッドと全く同じロジックで、バイトスライスb
の代わりに文字列s
を扱っています。 len(s)
(ユーザーが提供した文字列の長さ)を返すことで、io.Writer
のセマンティクスに準拠しています。
これらの変更により、log/syslog
パッケージの Writer
インターフェースを介してログを書き込むアプリケーションは、より正確で期待通りの戻り値を受け取ることができるようになり、エラーハンドリングやログの追跡が容易になります。
関連リンク
- Go言語
log/syslog
パッケージのドキュメント: https://pkg.go.dev/log/syslog - Go言語
fmt
パッケージのドキュメント: https://pkg.go.dev/fmt - Go言語
io
パッケージのドキュメント: https://pkg.go.dev/io - RFC 5424 - The Syslog Protocol: https://datatracker.ietf.org/doc/html/rfc5424
参考にした情報源リンク
- Go言語の公式ドキュメント (pkg.go.dev)
- RFC 5424 (IETF)
- Go言語のコミット履歴とコードレビューシステム (golang.org/cl)
- 一般的なプログラミングにおける
write
関数の戻り値に関する慣習 fmt.Fprintf
の動作に関するGo言語のドキュメント- Syslogプロトコルに関する一般的な知識
- Go言語の
io.Writer
インターフェースのセマンティクスに関する知識 - Go言語の
_
(ブランク識別子) の使用法に関する知識 - Go言語のエラーハンドリングの慣習に関する知識
- GitHubのコミットページ: https://github.com/golang/go/commit/3fce00d99e30d66f63f8e3cb85debc137329db0d
- Go CL 5644059: https://golang.org/cl/5644059 (これは古いCLシステムへのリンクであり、現在はGerritに移行しているため、直接アクセスできない場合がありますが、コミットメッセージに記載されているため参照しました。)