【问题】
折腾:
中的:
的时候,遇到一个很诡异的问题:
log4go输出到console的信息不全,
而对应的输出到log文件中的信息是全的。
此处的一些背景是:
之前通过:
【已解决】go语言中实现log信息同时输出到文件和控制台(命令行)
中的:
【记录】go语言中通过log4go实现同时输出log信息到log文件和console
已经是可以正常,即全部的log的信息,包括后续得到的cookie的各种信息,一共3个cookie,和后续的信息,
都是可以正常的输出到console和log文件中的。
然后此处经过了一段时间的调试,即,先后运行了很多次。
【折腾过程】
1.开始以为是log4go的那个rotate导致的呢,但是发现自己的代码中,已经是对于log文件的话,没用rotate:
gLogger.AddFilter("log", log4go.FINEST, log4go.NewFileLogWriter(logFilename, false))2.然后又以为是返回的cookie值的某个域,是nil,然后可能会导致log打印输出为空呢。
但是通过注释掉对应的行,结果还是输出信息不全。
3.经过多次尝试,发现同样的代码的前提下,多次运行,每次输出截止到的地方都不同。
4.后来又经过一番调试,最后发现:
现象是:
虽然代码都是正常的:
/*
* [File]
* EmulateLoginBaidu.go
*
* [Function]
* 【记录】用go语言实现模拟登陆百度
* https://www.crifan.org/emulate_login_baidu_using_go_language/
*
* [Version]
* 2013-09-19
*
* [Contact]
* https://www.crifan.org/about/me/
*/
package main
import (
"fmt"
//"builtin"
//"log"
"os"
"runtime"
"path"
"strings"
//"io"
"time"
"io/ioutil"
"net/http"
//"net/http/cookiejar"
//"sync"
//"net/url"
)
//import l4g "log4go.googlecode.com/hg"
//import l4g "code.google.com/p/log4go"
import "code.google.com/p/log4go"
/***************************************************************************************************
Global Variables
***************************************************************************************************/
var gCurCookies []*http.Cookie;
//var gLogger *log.Logger;
var gLogger log4go.Logger;
/***************************************************************************************************
Functions
***************************************************************************************************/
//do init before all others
func initAll(){
gCurCookies = nil
gLogger = nil
initLogger()
initCrifanLib()
}
//de-init for all
func deinitAll(){
gCurCookies = nil
if(nil == gLogger) {
//gLogger.Close();
gLogger = nil
}
}
//do some init for crifanLib
func initCrifanLib(){
gLogger.Debug("init for crifanLib")
gCurCookies = nil
return
}
//init for logger
func initLogger(){
var filenameOnly string
filenameOnly = GetCurFilename()
var logFilename string = filenameOnly + ".log";
//gLogger = log4go.NewLogger()
//gLogger = make(log4go.Logger)
//for console
//gLogger.AddFilter("stdout", log4go.INFO, log4go.NewConsoleLogWriter())
//gLogger.AddFilter("stdout", log4go.INFO, log4go.NewConsoleLogWriter())
gLogger = log4go.NewDefaultLogger(log4go.INFO)
//for log file
if _, err := os.Stat(logFilename); err == nil {
//fmt.Printf("found old log file %s, now remove it\n", logFilename)
os.Remove(logFilename)
}
//gLogger.AddFilter("logfile", log4go.FINEST, log4go.NewFileLogWriter(logFilename, true))
//gLogger.AddFilter("logfile", log4go.FINEST, log4go.NewFileLogWriter(logFilename, false))
gLogger.AddFilter("log", log4go.FINEST, log4go.NewFileLogWriter(logFilename, false))
gLogger.Info("Current time is : %s", time.Now().Format("15:04:05 MST 2006/01/02"))
return
}
// GetCurFilename
// Get current file name, without suffix
func GetCurFilename() string {
_, fulleFilename, _, _ := runtime.Caller(0)
//fmt.Println(fulleFilename)
var filenameWithSuffix string
filenameWithSuffix = path.Base(fulleFilename)
//fmt.Println("filenameWithSuffix=", filenameWithSuffix)
var fileSuffix string
fileSuffix = path.Ext(filenameWithSuffix)
//fmt.Println("fileSuffix=", fileSuffix)
var filenameOnly string
filenameOnly = strings.TrimSuffix(filenameWithSuffix, fileSuffix)
//fmt.Println("filenameOnly=", filenameOnly)
return filenameOnly
}
//get url response html
func GetUrlRespHtml(url string) string{
gLogger.Info("GetUrlRespHtml, url=%s", url)
var respHtml string = "";
resp, err := http.Get(url)
gLogger.Info("http.Get done")
gLogger.Info("resp.Header=%s", resp.Header)
gLogger.Info("resp.Status=%s", resp.Status)
if err != nil {
gLogger.Warn("http get url=%s response error=%s\n", url, err.Error())
}
// defer resp.Body.Close()
// gLogger.Info("defer resp.Body.Close done")
body, errReadAll := ioutil.ReadAll(resp.Body)
fmt.Println("ioutil.ReadAll done")
resp.Body.Close()
fmt.Println("resp.Body.Close done")
gLogger.Info("ioutil.ReadAll done")
fmt.Println("gLogger.Info done")
if errReadAll != nil {
gLogger.Warn("ioutil.ReadAll for url=%s got error=%s\n", url, errReadAll.Error())
}
//gLogger.Debug("body=%s\n", body)
gCurCookies = resp.Cookies()
gLogger.Info("resp.Cookies done")
fmt.Println("resp.Cookies done")
respHtml = string(body)
gLogger.Info("resp body []byte to string done")
//respHtml = "just for test log ok or not"
return respHtml
}
func printCurCookies() {
var cookieNum int = len(gCurCookies);
gLogger.Info("cookieNum=%d", cookieNum)
for i := 0; i < cookieNum; i++ {
var curCk *http.Cookie = gCurCookies[i];
//gLogger.Info("curCk.Raw=%s", curCk.Raw)
gLogger.Info("------ Cookie [%d]------", i)
gLogger.Info("Name\t=%s", curCk.Name)
gLogger.Info("Value\t=%s", curCk.Value)
gLogger.Info("Path\t=%s", curCk.Path)
gLogger.Info("Domain\t=%s", curCk.Domain)
gLogger.Info("Expires\t=%s", curCk.Expires)
gLogger.Info("RawExpires=%s", curCk.RawExpires)
gLogger.Info("MaxAge\t=%d", curCk.MaxAge)
gLogger.Info("Secure\t=%t", curCk.Secure)
gLogger.Info("HttpOnly=%t", curCk.HttpOnly)
gLogger.Info("Raw\t=%s", curCk.Raw)
gLogger.Info("Unparsed=%s", curCk.Unparsed)
}
}
func main() {
initAll()
gLogger.Info("this is EmulateLoginBaidu.go")
//step1: access baidu url to get cookie BAIDUID
var baiduMainUrl string
baiduMainUrl = "http://www.baidu.com/";
//baiduMainUrl := "http://www.baidu.com/";
//var baiduMainUrl string = "http://www.baidu.com/";
gLogger.Info("baiduMainUrl=%s", baiduMainUrl)
respHtml := GetUrlRespHtml(baiduMainUrl)
log4go.Debug("respHtml=%s", respHtml)
//gLogger.Debug("respHtml=%s", respHtml)
//printCurCookies()
//gLogger.Error("why log can not show ????????")
//var cookieNameListToCheck []string = ["BAIDUID"]
//toCheckCookieNameList := [1]string{"BAIDUID"}
toCheckCookieNameList := []string{"BAIDUID"}
toCheckCookieNum := len(toCheckCookieNameList)
gLogger.Info("toCheckCookieNum=%d\n", toCheckCookieNum) //toCheckCookieNum=1
//fmt.Printf("toCheckCookieNum=%d\n", toCheckCookieNum) //toCheckCookieNum=1
for i := 0; i < toCheckCookieNum; i++ {
cookieName := toCheckCookieNameList[i];
gLogger.Info("[%d]cookieName=%s", i, cookieName)
//fmt.Printf("[%d]cookieName=%s\n", i, cookieName) //[0]cookieName=BAIDUID
}
deinitAll()
}但是最终,只能输出到
resp.Cookies done
这一步,而后面的所有的信息,不论是info还是debug,不论是输出到console还是log文件,都是没了:
所以,很是奇怪。
至少,看起来,是log4go的bug。
无法正常输出log信息。
6.开始以为是:
body, errReadAll := ioutil.ReadAll(resp.Body)
的问题呢,结果上面代码证明了,也不是没有死在ReadAll,程序是可以正常运行下去的。
只是log4go有问题,无法输出而已。
7.所以,实在不行的话,搞得只能去重新使用旧的方法:
【记录】go语言中通过io的MultiWriter实现同时输出log信息到log文件和console
去实现输出log了。。。
虽然该法有缺点,但是估计应该会很稳定。
8.再继续去试试,看看能否找到根本原因,
到底是不是log4go的bug,还是其他问题。
9。也是看到了log4go中的:
func (ConsoleLogWriter) LogWritefunc (w ConsoleLogWriter) LogWrite(rec *LogRecord) This is the ConsoleLogWriter’s output method. This will block if the output buffer is full. |
感觉,或许真的是当前此处的log4go,内部是什么buffer满了。而导致无法继续输出了。
但是还是无法确定。
10.去试试,换个log文件,看看能否正常输出:
//var logFilename string = filenameOnly + ".log";
var logFilename string = "log4go_debug_1.log";看看结果如何,结果问题依旧,看来和log文件无关。
11.而且,之前也遇到这样的诡异事情。
对于如下代码,是把抓取网页的部分,都注释掉了:
/*
* [File]
* EmulateLoginBaidu.go
*
* [Function]
* 【记录】用go语言实现模拟登陆百度
* https://www.crifan.org/emulate_login_baidu_using_go_language/
*
* [Version]
* 2013-09-19
*
* [Contact]
* https://www.crifan.org/about/me/
*/
package main
import (
//"fmt"
//"builtin"
//"log"
"os"
"runtime"
"path"
"strings"
//"io"
"time"
//"io/ioutil"
"net/http"
//"net/http/cookiejar"
//"sync"
//"net/url"
)
//import l4g "log4go.googlecode.com/hg"
//import l4g "code.google.com/p/log4go"
import "code.google.com/p/log4go"
/***************************************************************************************************
Global Variables
***************************************************************************************************/
var gCurCookies []*http.Cookie;
//var gLogger *log.Logger;
var gLogger log4go.Logger;
/***************************************************************************************************
Functions
***************************************************************************************************/
//do init before all others
func initAll(){
gCurCookies = nil
gLogger = nil
initLogger()
initCrifanLib()
}
//de-init for all
func deinitAll(){
gCurCookies = nil
if(nil == gLogger) {
//gLogger.Close();
gLogger = nil
}
}
//do some init for crifanLib
func initCrifanLib(){
gLogger.Debug("init for crifanLib")
gCurCookies = nil
return
}
//init for logger
func initLogger(){
//var filenameOnly string
//filenameOnly = GetCurFilename()
//var logFilename string = filenameOnly + ".log";
var logFilename string = "log4go_debug_1.log";
//gLogger = log4go.NewLogger()
//gLogger = make(log4go.Logger)
//for console
//gLogger.AddFilter("stdout", log4go.INFO, log4go.NewConsoleLogWriter())
//gLogger.AddFilter("stdout", log4go.INFO, log4go.NewConsoleLogWriter())
gLogger = log4go.NewDefaultLogger(log4go.INFO)
//for log file
if _, err := os.Stat(logFilename); err == nil {
//fmt.Printf("found old log file %s, now remove it\n", logFilename)
os.Remove(logFilename)
}
//gLogger.AddFilter("logfile", log4go.FINEST, log4go.NewFileLogWriter(logFilename, true))
//gLogger.AddFilter("logfile", log4go.FINEST, log4go.NewFileLogWriter(logFilename, false))
gLogger.AddFilter("log", log4go.FINEST, log4go.NewFileLogWriter(logFilename, false))
gLogger.Info("Current time is : %s", time.Now().Format("15:04:05 MST 2006/01/02"))
return
}
// GetCurFilename
// Get current file name, without suffix
func GetCurFilename() string {
_, fulleFilename, _, _ := runtime.Caller(0)
//fmt.Println(fulleFilename)
var filenameWithSuffix string
filenameWithSuffix = path.Base(fulleFilename)
//fmt.Println("filenameWithSuffix=", filenameWithSuffix)
var fileSuffix string
fileSuffix = path.Ext(filenameWithSuffix)
//fmt.Println("fileSuffix=", fileSuffix)
var filenameOnly string
filenameOnly = strings.TrimSuffix(filenameWithSuffix, fileSuffix)
//fmt.Println("filenameOnly=", filenameOnly)
return filenameOnly
}
//get url response html
func GetUrlRespHtml(url string) string{
gLogger.Info("GetUrlRespHtml, url=%s", url)
var respHtml string = "";
// resp, err := http.Get(url)
// gLogger.Info("http.Get done")
// gLogger.Info("resp.Header=%s", resp.Header)
// gLogger.Info("resp.Status=%s", resp.Status)
// if err != nil {
// gLogger.Warn("http get url=%s response error=%s\n", url, err.Error())
// }
// // defer resp.Body.Close()
// // gLogger.Info("defer resp.Body.Close done")
// //body, errReadAll := ioutil.ReadAll(resp.Body)
// //body, _ := ioutil.ReadAll(resp.Body)
// fmt.Println("ioutil.ReadAll done")
// resp.Body.Close()
// fmt.Println("resp.Body.Close done")
// gLogger.Info("ioutil.ReadAll done")
// fmt.Println("gLogger.Info done")
// // if errReadAll != nil {
// // gLogger.Warn("ioutil.ReadAll for url=%s got error=%s\n", url, errReadAll.Error())
// // }
// //gLogger.Debug("body=%s\n", body)
// gCurCookies = resp.Cookies()
// gLogger.Info("resp.Cookies done")
// fmt.Println("resp.Cookies done")
respHtml = "just for test log ok or not"
//respHtml = string(body)
gLogger.Info("resp body []byte to string done")
return respHtml
}
func printCurCookies() {
var cookieNum int = len(gCurCookies);
gLogger.Info("cookieNum=%d", cookieNum)
for i := 0; i < cookieNum; i++ {
var curCk *http.Cookie = gCurCookies[i];
//gLogger.Info("curCk.Raw=%s", curCk.Raw)
gLogger.Info("------ Cookie [%d]------", i)
gLogger.Info("Name\t=%s", curCk.Name)
gLogger.Info("Value\t=%s", curCk.Value)
gLogger.Info("Path\t=%s", curCk.Path)
gLogger.Info("Domain\t=%s", curCk.Domain)
gLogger.Info("Expires\t=%s", curCk.Expires)
gLogger.Info("RawExpires=%s", curCk.RawExpires)
gLogger.Info("MaxAge\t=%d", curCk.MaxAge)
gLogger.Info("Secure\t=%t", curCk.Secure)
gLogger.Info("HttpOnly=%t", curCk.HttpOnly)
gLogger.Info("Raw\t=%s", curCk.Raw)
gLogger.Info("Unparsed=%s", curCk.Unparsed)
}
}
func main() {
initAll()
gLogger.Info("this is EmulateLoginBaidu.go")
//step1: access baidu url to get cookie BAIDUID
var baiduMainUrl string
baiduMainUrl = "http://www.baidu.com/";
//baiduMainUrl := "http://www.baidu.com/";
//var baiduMainUrl string = "http://www.baidu.com/";
gLogger.Info("baiduMainUrl=%s", baiduMainUrl)
respHtml := GetUrlRespHtml(baiduMainUrl)
log4go.Debug("respHtml=%s", respHtml)
//gLogger.Debug("respHtml=%s", respHtml)
//printCurCookies()
//gLogger.Error("why log can not show ????????")
//var cookieNameListToCheck []string = ["BAIDUID"]
//toCheckCookieNameList := [1]string{"BAIDUID"}
toCheckCookieNameList := []string{"BAIDUID"}
toCheckCookieNum := len(toCheckCookieNameList)
gLogger.Info("toCheckCookieNum=%d\n", toCheckCookieNum) //toCheckCookieNum=1
//fmt.Printf("toCheckCookieNum=%d\n", toCheckCookieNum) //toCheckCookieNum=1
for i := 0; i < toCheckCookieNum; i++ {
cookieName := toCheckCookieNameList[i];
gLogger.Info("[%d]cookieName=%s", i, cookieName)
//fmt.Printf("[%d]cookieName=%s\n", i, cookieName) //[0]cookieName=BAIDUID
}
deinitAll()
}结果,竟然输出是:
console中,所有的打印信息,都没有了。。。
包括fmt的和log4go的。。。
全都是空的
而对应的log文件中,输出的是正的:
11.想办法,去删除log4go,再重新安装试试。
然后接着还是问题依旧:
E:\Dev_Root\go\src\EmulateLoginBaidu>go run EmulateLoginBaidu.go E:\Dev_Root\go\src\EmulateLoginBaidu>
12.此处,console和log文件:
log4go_debug_1.log
都是空的,都没有输出任何信息。
感觉像是:
要么是log4go,内部弄成死锁性质的,导致无法输出,或者是block掉了。
13.现在去试试:
只保留log4go中,初始化的console,去掉log文件的部分:
var logFilename string = "log4go_debug_1.log";
//gLogger = log4go.NewLogger()
//gLogger = make(log4go.Logger)
//for console
//gLogger.AddFilter("stdout", log4go.INFO, log4go.NewConsoleLogWriter())
//gLogger.AddFilter("stdout", log4go.INFO, log4go.NewConsoleLogWriter())
gLogger = log4go.NewDefaultLogger(log4go.INFO)
//for log file
if _, err := os.Stat(logFilename); err == nil {
//fmt.Printf("found old log file %s, now remove it\n", logFilename)
os.Remove(logFilename)
}
//gLogger.AddFilter("logfile", log4go.FINEST, log4go.NewFileLogWriter(logFilename, true))
//gLogger.AddFilter("logfile", log4go.FINEST, log4go.NewFileLogWriter(logFilename, false))
//gLogger.AddFilter("log", log4go.FINEST, log4go.NewFileLogWriter(logFilename, false))
gLogger.Info("Current time is : %s", time.Now().Format("15:04:05 MST 2006/01/02"))看看结果如何:
问题依旧。
此刻,的确没有创建什么log文件了。
并且还是之前的:console中也无输出了。
14.反过来:保留log文件,去掉console:
var logFilename string = "log4go_debug_1.log";
//gLogger = log4go.NewLogger()
gLogger = make(log4go.Logger)
//for console
//gLogger.AddFilter("stdout", log4go.INFO, log4go.NewConsoleLogWriter())
//gLogger.AddFilter("stdout", log4go.INFO, log4go.NewConsoleLogWriter())
//gLogger = log4go.NewDefaultLogger(log4go.INFO)
//for log file
if _, err := os.Stat(logFilename); err == nil {
//fmt.Printf("found old log file %s, now remove it\n", logFilename)
os.Remove(logFilename)
}
//gLogger.AddFilter("logfile", log4go.FINEST, log4go.NewFileLogWriter(logFilename, true))
//gLogger.AddFilter("logfile", log4go.FINEST, log4go.NewFileLogWriter(logFilename, false))
gLogger.AddFilter("log", log4go.FINEST, log4go.NewFileLogWriter(logFilename, false))
gLogger.Info("Current time is : %s", time.Now().Format("15:04:05 MST 2006/01/02"))看看结果如何:
结果是log文件:log4go_debug_1.log
虽然被创建了。
结果还是空的。
console中,自然还是没有输出。
15。看到:
Re: [go-nuts] log4go flush – msg#01802
这人,遇到和我,有点点类似的问题:
其要输出的hello world,由于程序的exit,导致无法输出了:正常的话,肯定是应该可以的。
那我此处,去试试,加上exit,看看什么效果。
//init for logger
func initLogger(){
//var filenameOnly string
//filenameOnly = GetCurFilename()
//var logFilename string = filenameOnly + ".log";
var logFilename string = "log4go_debug_1.log";
//gLogger = log4go.NewLogger()
gLogger = make(log4go.Logger)
//for console
//gLogger.AddFilter("stdout", log4go.INFO, log4go.NewConsoleLogWriter())
//gLogger.AddFilter("stdout", log4go.INFO, log4go.NewConsoleLogWriter())
//gLogger = log4go.NewDefaultLogger(log4go.INFO)
//for log file
if _, err := os.Stat(logFilename); err == nil {
//fmt.Printf("found old log file %s, now remove it\n", logFilename)
os.Remove(logFilename)
}
//gLogger.AddFilter("logfile", log4go.FINEST, log4go.NewFileLogWriter(logFilename, true))
//gLogger.AddFilter("logfile", log4go.FINEST, log4go.NewFileLogWriter(logFilename, false))
gLogger.AddFilter("log", log4go.FINEST, log4go.NewFileLogWriter(logFilename, false))
gLogger.Info("Current time is : %s", time.Now().Format("15:04:05 MST 2006/01/02"))
exit();
return
}结果是:
根本没exit函数:
.\EmulateLoginBaidu.go:97: undefined: exit
16.换成log4go的close试试:
//init for logger
func initLogger(){
//var filenameOnly string
//filenameOnly = GetCurFilename()
//var logFilename string = filenameOnly + ".log";
var logFilename string = "log4go_debug_1.log";
//gLogger = log4go.NewLogger()
gLogger = make(log4go.Logger)
//for console
//gLogger.AddFilter("stdout", log4go.INFO, log4go.NewConsoleLogWriter())
//gLogger.AddFilter("stdout", log4go.INFO, log4go.NewConsoleLogWriter())
//gLogger = log4go.NewDefaultLogger(log4go.INFO)
//for log file
if _, err := os.Stat(logFilename); err == nil {
//fmt.Printf("found old log file %s, now remove it\n", logFilename)
os.Remove(logFilename)
}
//gLogger.AddFilter("logfile", log4go.FINEST, log4go.NewFileLogWriter(logFilename, true))
//gLogger.AddFilter("logfile", log4go.FINEST, log4go.NewFileLogWriter(logFilename, false))
gLogger.AddFilter("log", log4go.FINEST, log4go.NewFileLogWriter(logFilename, false))
gLogger.Info("Current time is : %s", time.Now().Format("15:04:05 MST 2006/01/02"))
//exit();
gLogger.Close();
return
}结果是:
问题依旧。
17.参考:
http://godoc.org/code.google.com/p/log4go#Exit
去试试:
//gLogger.Close();
log4go.Exit();结果是:
问题依旧。
18.后来,看到了:
中的解释:
(1)log4go的文档,很明显不是最新的,用的函数也是旧的函数:这点我早已发现,并且改正了;
(2)存在flush的bug,main函数退出太快的话,会导致无输出,或者输出内容部分丢失:我此处就是这样的问题。
(3)参考那人的解释,去手动加上flush的动作试试:
在main函数最后所调用的deinitAll函数中加上:
//de-init for all
func deinitAll(){
gCurCookies = nil
if(nil == gLogger) {
gLogger.Close();
os.Stdout.Sync() //try manually flush, hope can fix log4go's bug
gLogger = nil
}
}看看效果:
结果还是无输出。。。
19.想起来了,此处是刚才把stdout禁止了。
现在去加上:
//init for logger
func initLogger(){
//var filenameOnly string
//filenameOnly = GetCurFilename()
//var logFilename string = filenameOnly + ".log";
var logFilename string = "log4go_debug_1.log";
//gLogger = log4go.NewLogger()
//gLogger = make(log4go.Logger)
//for console
//gLogger.AddFilter("stdout", log4go.INFO, log4go.NewConsoleLogWriter())
//gLogger.AddFilter("stdout", log4go.INFO, log4go.NewConsoleLogWriter())
gLogger = log4go.NewDefaultLogger(log4go.INFO)
//for log file
if _, err := os.Stat(logFilename); err == nil {
//fmt.Printf("found old log file %s, now remove it\n", logFilename)
os.Remove(logFilename)
}
//gLogger.AddFilter("logfile", log4go.FINEST, log4go.NewFileLogWriter(logFilename, true))
//gLogger.AddFilter("logfile", log4go.FINEST, log4go.NewFileLogWriter(logFilename, false))
gLogger.AddFilter("log", log4go.FINEST, log4go.NewFileLogWriter(logFilename, false))
gLogger.Info("Current time is : %s", time.Now().Format("15:04:05 MST 2006/01/02"))
//exit();
//gLogger.Close();
//log4go.Exit();
return
}结果是:
问题依旧,还是无输出。。。
20.去试试,在main函数最后,加上sleep的代码:
time.Sleep(1000 * time.Millisecond)
结果是
真的可以了!!!
即:
不论是log文件,还是console,都可以正常输出log信息了。。。
21.再去注释掉sleep的话:
//time.Sleep(1000 * time.Millisecond)
看看结果:
果然真的没有输出。
22.再去对于sleep时间改短点,比如只有100毫秒:
//time.Sleep(1000 * time.Millisecond)
time.Sleep(100 * time.Millisecond)结果是:
也正常,可以输出去全部log信息。
23.继续去缩短sleep的时间,看看10毫秒如何:
//time.Sleep(1000 * time.Millisecond)
//time.Sleep(100 * time.Millisecond)
time.Sleep(10 * time.Millisecond)结果也是可以的。
再次证明:
log4go,的确是有bug;
而手动加stdout的sync是没用的
但是加上sleep就有用,
而且是sleep一个很短的时间,比如10毫秒,就足够了,就可以保证所有的log信息正常输出了。
24.再去把之前正常的代码,都加上:
/*
* [File]
* EmulateLoginBaidu.go
*
* [Function]
* 【记录】用go语言实现模拟登陆百度
* https://www.crifan.org/emulate_login_baidu_using_go_language/
*
* [Version]
* 2013-09-19
*
* [Contact]
* https://www.crifan.org/about/me/
*/
package main
import (
//"fmt"
//"builtin"
//"log"
"os"
"runtime"
"path"
"strings"
"time"
//"io"
"io/ioutil"
"net/http"
//"net/http/cookiejar"
//"sync"
//"net/url"
)
//import l4g "log4go.googlecode.com/hg"
//import l4g "code.google.com/p/log4go"
import "code.google.com/p/log4go"
/***************************************************************************************************
Global Variables
***************************************************************************************************/
var gCurCookies []*http.Cookie;
var gLogger log4go.Logger;
/***************************************************************************************************
Functions
***************************************************************************************************/
//do init before all others
func initAll(){
gCurCookies = nil
gLogger = nil
initLogger()
initCrifanLib()
}
//de-init for all
func deinitAll(){
gCurCookies = nil
if(nil == gLogger) {
gLogger.Close();
//os.Stdout.Sync() //try manually flush, but can not fix log4go's flush bug
gLogger = nil
}
}
//do some init for crifanLib
func initCrifanLib(){
gLogger.Debug("init for crifanLib")
gCurCookies = nil
return
}
//init for logger
func initLogger(){
var filenameOnly string = GetCurFilename()
var logFilename string = filenameOnly + ".log";
//var logFilename string = "log4go_debug_1.log";
//gLogger = log4go.NewLogger()
//gLogger = make(log4go.Logger)
//for console
//gLogger.AddFilter("stdout", log4go.INFO, log4go.NewConsoleLogWriter())
//gLogger.AddFilter("stdout", log4go.INFO, log4go.NewConsoleLogWriter())
gLogger = log4go.NewDefaultLogger(log4go.INFO)
//for log file
if _, err := os.Stat(logFilename); err == nil {
//fmt.Printf("found old log file %s, now remove it\n", logFilename)
os.Remove(logFilename)
}
//gLogger.AddFilter("logfile", log4go.FINEST, log4go.NewFileLogWriter(logFilename, true))
//gLogger.AddFilter("logfile", log4go.FINEST, log4go.NewFileLogWriter(logFilename, false))
gLogger.AddFilter("log", log4go.FINEST, log4go.NewFileLogWriter(logFilename, false))
gLogger.Info("Current time is : %s", time.Now().Format("15:04:05 MST 2006/01/02"))
return
}
// GetCurFilename
// Get current file name, without suffix
func GetCurFilename() string {
_, fulleFilename, _, _ := runtime.Caller(0)
//fmt.Println(fulleFilename)
var filenameWithSuffix string
filenameWithSuffix = path.Base(fulleFilename)
//fmt.Println("filenameWithSuffix=", filenameWithSuffix)
var fileSuffix string
fileSuffix = path.Ext(filenameWithSuffix)
//fmt.Println("fileSuffix=", fileSuffix)
var filenameOnly string
filenameOnly = strings.TrimSuffix(filenameWithSuffix, fileSuffix)
//fmt.Println("filenameOnly=", filenameOnly)
return filenameOnly
}
//get url response html
func GetUrlRespHtml(url string) string{
gLogger.Info("GetUrlRespHtml, url=%s", url)
var respHtml string = "";
resp, err := http.Get(url)
//gLogger.Info("http.Get done")
if err != nil {
gLogger.Warn("http get url=%s response error=%s\n", url, err.Error())
}
gLogger.Debug("resp.Header=%s", resp.Header)
gLogger.Debug("resp.Status=%s", resp.Status)
defer resp.Body.Close()
// gLogger.Info("defer resp.Body.Close done")
body, errReadAll := ioutil.ReadAll(resp.Body)
//body, _ := ioutil.ReadAll(resp.Body)
//fmt.Println("ioutil.ReadAll done")
//fmt.Println("resp.Body.Close done")
//gLogger.Info("ioutil.ReadAll done")
//fmt.Println("gLogger.Info done")
if errReadAll != nil {
gLogger.Warn("get response for url=%s got error=%s\n", url, errReadAll.Error())
}
//gLogger.Debug("body=%s\n", body)
gCurCookies = resp.Cookies()
//gLogger.Info("resp.Cookies done")
//fmt.Println("resp.Cookies done")
//respHtml = "just for test log ok or not"
respHtml = string(body)
//gLogger.Info("resp body []byte to string done")
return respHtml
}
func printCurCookies() {
var cookieNum int = len(gCurCookies);
gLogger.Info("cookieNum=%d", cookieNum)
for i := 0; i < cookieNum; i++ {
var curCk *http.Cookie = gCurCookies[i];
//gLogger.Info("curCk.Raw=%s", curCk.Raw)
gLogger.Info("------ Cookie [%d]------", i)
gLogger.Info("Name\t=%s", curCk.Name)
gLogger.Info("Value\t=%s", curCk.Value)
gLogger.Info("Path\t=%s", curCk.Path)
gLogger.Info("Domain\t=%s", curCk.Domain)
gLogger.Info("Expires\t=%s", curCk.Expires)
gLogger.Info("RawExpires=%s", curCk.RawExpires)
gLogger.Info("MaxAge\t=%d", curCk.MaxAge)
gLogger.Info("Secure\t=%t", curCk.Secure)
gLogger.Info("HttpOnly=%t", curCk.HttpOnly)
gLogger.Info("Raw\t=%s", curCk.Raw)
gLogger.Info("Unparsed=%s", curCk.Unparsed)
}
}
func main() {
initAll()
gLogger.Info("this is EmulateLoginBaidu.go")
//step1: access baidu url to get cookie BAIDUID
var baiduMainUrl string
baiduMainUrl = "http://www.baidu.com/";
//baiduMainUrl := "http://www.baidu.com/";
//var baiduMainUrl string = "http://www.baidu.com/";
gLogger.Info("baiduMainUrl=%s", baiduMainUrl)
respHtml := GetUrlRespHtml(baiduMainUrl)
gLogger.Debug("respHtml=%s", respHtml)
printCurCookies()
//gLogger.Error("why log can not show ????????")
//var cookieNameListToCheck []string = ["BAIDUID"]
//toCheckCookieNameList := [1]string{"BAIDUID"}
toCheckCookieNameList := []string{"BAIDUID"}
toCheckCookieNum := len(toCheckCookieNameList)
gLogger.Info("toCheckCookieNum=%d", toCheckCookieNum) //toCheckCookieNum=1
//fmt.Printf("toCheckCookieNum=%d\n", toCheckCookieNum) //toCheckCookieNum=1
for i := 0; i < toCheckCookieNum; i++ {
cookieName := toCheckCookieNameList[i];
gLogger.Info("[%d]cookieName=%s", i, cookieName)
//fmt.Printf("[%d]cookieName=%s\n", i, cookieName) //[0]cookieName=BAIDUID
}
deinitAll()
//【workaround】go语言中用log4go输出信息时有bug:只输出部分信息,甚至是无任何输出
//https://www.crifan.org/go_language_log4go_only_output_part_info/
time.Sleep(10 * time.Millisecond)
}看看结果是否也正常:
结果是:
偶尔,还是会输出内容不全的。
大部分的时候,已经正常了,够用了。
所以,看起来,至少此处的,sleep给的10ms,还是不太够。
所以,还是去改为更大点的时间,比如之前的100ms:
【总结】
至此,终于清楚根本原因了:
log4go,本身这个库还是不错的,
只不过,到目前为止:2013-09-20
还是有bug的,其中一个bug是:
其内部是通过channel去将log内容输出,到console和log文件中的;
而如果你的程序(main函数)退出的太快
就会导致log信息,来不及输出,你的程序就退出了。
从而导致:
你用log4go输出的信息,部分的,甚至全部的,都丢失了
从而在你的console和(或)你的log文件中,看不到log信息
解决办法:
在你的main函数,退出之前,加上对应的sleep,即可。
比如:
time.Sleep(100 * time.Millisecond)
即可保证:
你的log信息,都可以正常输出。
感慨:
log4go,不错的模块,可是这样的bug却浪费了我大量的时间。。。哎,无语。。。
转载请注明:在路上 » 【workaround】go语言中用log4go输出信息时有bug:只输出部分信息,甚至是无任何输出