【文法系】【go】基本15:ロギングとエラーハンドリング
1.log(ロギング)
以下のように、該当するファイルがない場合、エラー文を表示して、終了する際などエラーハンドリングに使用。
主な使用場面
package main import ( "io" "log" "os" ) func loggingSettings(logFile string){ logfile, _ := os.OpenFile(logFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) multiLogFile := io.MultiWriter(os.Stdout, logfile) log.SetFlags(log.Ldate | log.Ltime | log.Llongfile) log.SetOutput(multiLogFile) } func main() { loggingSettings("test.log") // test.logに以下のエラーハンドリングの結果を出力 _, err := os.Open("xxxxxx") if err != nil{ log.Fatalln("Exit", err) } }
▼ 出力
2020/02/24 06:53:21 /home/vagrant/workspace/src/myapp/lesson.go:20: Exit open xxxxxx: no such file or directory exit status 1
<test.log>
2020/02/24 06:53:21 /home/vagrant/workspace/src/myapp/lesson.go:20: Exit open xxxxxx: no such file or directory
⑴ 基本的な書き方
例①
package main import ( "log" "fmt" ) func main() { log.Println("logging!") log.Printf("%T %v", "test", "test") log.Fatalln("error!") fmt.Println("OK!") // 実行されない }
▼ 実行
$ go run lesson.go 2020/02/24 06:27:29 logging! 2020/02/24 06:27:29 string test 2020/02/24 06:27:29 error! exit status 1
《解説》
「log.Fatalln()」と同様に、「log.Fatalf()」もそこでコードは終了する。
func main() { log.Println("logging!") log.Printf("%T %v", "test", "test") log.Fatalf("%T %v", "test2", "test2") fmt.Println("OK!") // 実行されない }
▼ 出力
2020/02/24 06:38:26 logging! 2020/02/24 06:38:26 string test 2020/02/24 06:38:26 string test2 exit status 1
2.エラーハンドリング
説明
⑴ 基本的な書き方
例①
package main import ( "fmt" "log" "os" ) func main() { file, err := os.Open("./lesson.go") if err != nil{ log.Fatalln("Error!") } defer file.Close() data := make([]byte, 100) count, err := file.Read(data) if err != nil{ log.Fatalln("Error") } fmt.Println(count, string(data)) err = os.Chdir("test") // Chdirはchangeディレクトリの意 if err != nil{ log.Fatalln("Error") } }
▼ 実行
$ go run lesson.go 100 package main import ( "fmt" "log" "os" ) func main() { file, err := os.Open("./les 2020/02/24 07:52:42 Error exit status 1
《解説》
:=(イニシャライズのショートデクレアレーションは)が最低一つイニシャライズする変数があれば良いため、今回のケースでも使用できる。
つまり、「count, err := file.Read(data)」のcountはイニシャライズされ、errはすでに定義されているため、override(上書き)される。
なお、os.Chdir()については、エラーかどうかのみ返すため、変数は一つとなり、errはすでに定義済みのため、=でoverrideする。
2.panicとrecover
panic:自分で例外を投げられるため、そこでプログラムは強制終了される。
⑴ panic
例①
package main import "fmt" func thirdPartyConnectDB(){ panic("Unable to connect database!") } func save(){ thirdPartyConnectDB() } func main() { save() fmt.Println("OK?") }
▼ 実行
$ go run lesson.go panic: Unable to connect database! goroutine 1 [running]: main.thirdPartyConnectDB() /home/vagrant/workspace/src/myapp/lesson.go:6 +0x39 main.save() /home/vagrant/workspace/src/myapp/lesson.go:10 +0x20 main.main() /home/vagrant/workspace/src/myapp/lesson.go:14 +0x22 exit status 2
《解説》
save関数でthirdPartyConnectDB関数を呼び出し、panicが実行されるため、そこでプログラムが終了し、main関数にあるfmt.Println("OK?")は実行されない。
⑵ recover
例①
package main import "fmt" func thirdPartyConnectDB(){ panic("Unable to connect database!") } func save(){ defer func(){ s := recover() fmt.Println(s) }() thirdPartyConnectDB() } func main() { save() fmt.Println("OK?") }
▼ 実行
$ go run lesson.go Unable to connect database! OK?
《解説》
save関数でthirdPartyConnectDB関数を呼び出し、panicが実行されるが、save関数では、thirdPartyConnectDB関数よりも先にdefer func()が記述されているため、panicで発生した例外の内容のみrecover()が受け取り、Printlnで出力する(プログラムの終了はさせない)。プログラムは終了しないため、main関数のfmt.Println("OK?")も実行される。
【補足】
以下のように、panicを呼び出すthirdPartyConnectDB関数をdefer func()よりも先に書くと、panicでプログラムが終了してしまうため注意。
func save(){ thirdPartyConnectDB() defer func(){ s := recover() fmt.Println(s) }() }
▼ 出力
panic: Unable to connect database! goroutine 1 [running]: main.thirdPartyConnectDB() /home/vagrant/workspace/src/myapp/lesson.go:6 +0x39 main.save() /home/vagrant/workspace/src/myapp/lesson.go:10 +0x22 main.main() /home/vagrant/workspace/src/myapp/lesson.go:18 +0x22 exit status 2