├── .gitignore ├── README.md ├── middleware ├── workpool.go └── channel.go ├── fgupiao.go ├── basic ├── request.go ├── response.go ├── config.go └── logging.go ├── util └── stringConv.go ├── res └── share.go ├── downloader └── downloader.go ├── analyzer └── analyzer.go └── controller └── controller.go /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/* 2 | 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gofgupiao 2 | go股票数据爬虫 3 | -------------------------------------------------------------------------------- /middleware/workpool.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | // 2019.02.22 3 | type WorkPool struct { 4 | // 5 | } 6 | 7 | func NewWorkPool() *WorkPool { 8 | return &WorkPool{} 9 | } 10 | 11 | func (this *WorkPool) Pool(num int, work func()) { 12 | for i := 0; i < num; i++ { 13 | go work() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /fgupiao.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // 2019.02.22 4 | import ( 5 | "fmt" 6 | "github.com/itzujun/gofgupiao/controller" 7 | ) 8 | 9 | func main() { 10 | url := "http://quote.eastmoney.com/stocklist.html" 11 | fmt.Println("url:", url) 12 | ctrl := controller.NewController(url) 13 | fmt.Print(ctrl) 14 | ctrl.Go() 15 | } 16 | -------------------------------------------------------------------------------- /basic/request.go: -------------------------------------------------------------------------------- 1 | package basic 2 | // 2019.02.22 3 | import "net/http" 4 | 5 | type Request struct { 6 | httpReq *http.Request 7 | index uint32 8 | } 9 | 10 | func NewRequest(httpReq *http.Request, index uint32) *Request { 11 | return &Request{httpReq: httpReq} 12 | } 13 | 14 | func (req *Request) GetReq() *http.Request { 15 | return req.httpReq 16 | } 17 | 18 | func (req *Request) GetIndex() uint32 { 19 | return req.index 20 | } 21 | -------------------------------------------------------------------------------- /basic/response.go: -------------------------------------------------------------------------------- 1 | package basic 2 | // 2019.02.22 3 | import "net/http" 4 | 5 | type Response struct { 6 | httpRes *http.Response 7 | index uint32 8 | } 9 | 10 | func NewResponse(httpRes *http.Response, index uint32) *Response { 11 | return &Response{httpRes: httpRes, index: index} 12 | } 13 | 14 | func (res *Response) GetRes() *http.Response { 15 | return res.httpRes 16 | } 17 | 18 | func (res *Response) GetIndex() uint32 { 19 | return res.index 20 | } 21 | -------------------------------------------------------------------------------- /util/stringConv.go: -------------------------------------------------------------------------------- 1 | package util 2 | // 2019.02.22 3 | import ( 4 | "github.com/axgle/mahonia" 5 | "strconv" 6 | "time" 7 | ) 8 | 9 | func ConvertToString(src string, srcCode string, tagCode string) string { 10 | srcCoder := mahonia.NewDecoder(srcCode) 11 | srcResult := srcCoder.ConvertString(src) 12 | tagCoder := mahonia.NewDecoder(tagCode) 13 | _, cdata, _ := tagCoder.Translate([]byte(srcResult), true) 14 | result := string(cdata) 15 | return result 16 | } 17 | 18 | func GetTimeStap() string { 19 | msec := time.Now().UnixNano() / 1e9 20 | return strconv.FormatInt(msec, 10) //时间戳 21 | } 22 | -------------------------------------------------------------------------------- /basic/config.go: -------------------------------------------------------------------------------- 1 | package basic 2 | // 2019.02.22 3 | type config struct { 4 | flag bool 5 | Name string 6 | StartUrl string 7 | HttpHead map[string]string 8 | RequestNum int 9 | RequestMethod string 10 | } 11 | 12 | var Config *config = &config{flag: true} 13 | 14 | func InitConfig() { 15 | if Config.flag == false { 16 | return 17 | } 18 | Config.HttpHead = make(map[string]string) 19 | if Config.Name == "" { 20 | Config.Name = "gofgupiao" 21 | } 22 | if Config.RequestNum == 0 { 23 | Config.RequestNum = 50 24 | } 25 | if Config.RequestMethod == "" { 26 | Config.RequestMethod = "GET" 27 | } 28 | Config.flag = true 29 | } 30 | -------------------------------------------------------------------------------- /res/share.go: -------------------------------------------------------------------------------- 1 | package res 2 | // 2019.02.22 3 | import "strings" 4 | 5 | type Shares struct { 6 | Name string 7 | Code string 8 | Url string 9 | ApiCode string 10 | } 11 | 12 | type SharesRes struct { 13 | Name string 14 | Code string 15 | Open string 16 | High string 17 | Close string 18 | Volume string 19 | PreClose string 20 | } 21 | 22 | func NewShares() *Shares { 23 | return &Shares{} 24 | } 25 | 26 | func NewSharesRes() *SharesRes { 27 | return &SharesRes{} 28 | } 29 | 30 | func (sh *Shares) GetLinkCode() string { 31 | liCode := strings.Split(sh.Url, "/") 32 | return strings.Split(liCode[len(liCode)-1], ".")[0] 33 | 34 | } 35 | -------------------------------------------------------------------------------- /downloader/downloader.go: -------------------------------------------------------------------------------- 1 | package downloader 2 | // 2019.02.22 3 | import ( 4 | "github.com/itzujun/gofgupiao/basic" 5 | "net/http" 6 | ) 7 | 8 | type GenDownloader interface { 9 | Download(req *basic.Request) *basic.Response 10 | } 11 | 12 | type Downloader struct { 13 | client *http.Client 14 | } 15 | 16 | func NewDownloader() GenDownloader { 17 | return &Downloader{&http.Client{}} 18 | } 19 | 20 | func (this *Downloader) Download(req *basic.Request) *basic.Response { 21 | for k, v := range basic.Config.HttpHead { 22 | req.GetReq().Header.Set(k, v) 23 | } 24 | httpRes, err := this.client.Do(req.GetReq()) 25 | if err != nil { 26 | return nil 27 | } 28 | return basic.NewResponse(httpRes, req.GetIndex()) 29 | } 30 | -------------------------------------------------------------------------------- /middleware/channel.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | // 2019.02.22 3 | import ( 4 | "github.com/itzujun/gofgupiao/basic" 5 | "github.com/itzujun/gofgupiao/res" 6 | ) 7 | 8 | type Channel struct { 9 | reqpchan chan basic.Request //请求 10 | respchan chan basic.Response //结果 11 | sharechan chan []res.Shares //股票infos 12 | ch chan res.Shares //单一股票info 13 | } 14 | 15 | func NewChannel() *Channel { 16 | return &Channel{ 17 | make(chan basic.Request, 1), 18 | make(chan basic.Response, 1), 19 | make(chan []res.Shares, 10), 20 | make(chan res.Shares, 10), 21 | } 22 | } 23 | 24 | func (this *Channel) ReqChan() chan basic.Request { 25 | return this.reqpchan 26 | } 27 | 28 | func (this *Channel) RespChan() chan basic.Response { 29 | return this.respchan 30 | } 31 | 32 | func (this *Channel) RespShares() chan []res.Shares { 33 | return this.sharechan 34 | } 35 | 36 | func (this *Channel) RespCh() chan res.Shares { 37 | return this.ch 38 | } 39 | -------------------------------------------------------------------------------- /analyzer/analyzer.go: -------------------------------------------------------------------------------- 1 | package analyzer 2 | // 2019.02.22 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/PuerkitoBio/goquery" 7 | "github.com/itzujun/gofgupiao/res" 8 | "github.com/itzujun/gofgupiao/util" 9 | "io/ioutil" 10 | "net/http" 11 | "strings" 12 | ) 13 | 14 | type GenAnalyzer interface { 15 | AnalyzeHtml(httpRes *http.Response) []res.Shares 16 | AnalyzeApi(httpRes *http.Response, shares res.Shares) *res.SharesRes 17 | } 18 | 19 | type Analyzer struct { 20 | GenAnalyzer 21 | } 22 | 23 | func NewAnalyzer() GenAnalyzer { 24 | return &Analyzer{} 25 | } 26 | 27 | //Api解析 28 | func (self *Analyzer) AnalyzeApi(httpResp *http.Response, shares res.Shares) *res.SharesRes { 29 | shRes := &res.SharesRes{} 30 | respstream, err := ioutil.ReadAll(httpResp.Body) 31 | if err != nil { 32 | fmt.Print("error:", err.Error()) 33 | } 34 | recpmap := make(map[string]interface{}) 35 | err = json.Unmarshal(respstream, &recpmap) 36 | data, ok := recpmap["mashData"] 37 | if err != nil || ok == false { 38 | return shRes 39 | } 40 | value, _ := data.([]interface{}) 41 | val, _ := value[0].(map[string]interface{}) 42 | kline, _ := val["kline"] 43 | if kVal, ok := kline.(map[string]interface{}); ok { 44 | fmt.Println(shares.Name, shares.Code, kVal["open"], kVal["high"], kVal["open"], kVal["close"], kVal["volume"], kVal["preClose"]) 45 | shRes = &res.SharesRes{Name: shares.Name, Code: shares.Code} 46 | } 47 | return shRes 48 | } 49 | 50 | //用于解析页面 51 | func (self *Analyzer) AnalyzeHtml(httpRes *http.Response) []res.Shares { 52 | defer httpRes.Body.Close() 53 | sh := []res.Shares{} 54 | doc, _ := goquery.NewDocumentFromReader(httpRes.Body) 55 | doc.Find("div.quotebody li").Each(func(i int, s *goquery.Selection) { 56 | band := s.Find("a").Text() 57 | if url, exists := s.Find("a").Attr("href"); exists { 58 | band = util.ConvertToString(band, "gbk", "utf-8") 59 | band = strings.Replace(band, ")", "", -1) 60 | recv := strings.Split(band, "(") 61 | liCode := strings.Split(url, "/") 62 | ApiCode := strings.Split(liCode[len(liCode)-1], ".")[0] 63 | if strings.HasPrefix(ApiCode, "sz300") { 64 | sh = append(sh, res.Shares{recv[0], recv[1], url, ApiCode}) 65 | } 66 | } 67 | }) 68 | return sh 69 | } 70 | -------------------------------------------------------------------------------- /controller/controller.go: -------------------------------------------------------------------------------- 1 | package controller 2 | // 2019.02.22 3 | import ( 4 | "fmt" 5 | "github.com/itzujun/gofgupiao/analyzer" 6 | "github.com/itzujun/gofgupiao/basic" 7 | "github.com/itzujun/gofgupiao/downloader" 8 | "github.com/itzujun/gofgupiao/middleware" 9 | "github.com/itzujun/gofgupiao/res" 10 | "github.com/itzujun/gofgupiao/util" 11 | "net/http" 12 | "sync" 13 | ) 14 | 15 | var wg sync.WaitGroup 16 | 17 | var logger = basic.NewSimpleLogger() // 日志记录器 18 | 19 | type Controller struct { 20 | StartUrl string //初始爬行Url 21 | Downloader downloader.GenDownloader // 下载器 22 | Channel *middleware.Channel //管道 23 | WorkPool *middleware.WorkPool //工作池 24 | Parser analyzer.GenAnalyzer //解析页函数 25 | } 26 | 27 | func NewController(startUrl string) *Controller { 28 | return &Controller{StartUrl: startUrl} 29 | } 30 | 31 | func (ctrl *Controller) Go() { 32 | basic.Config.StartUrl = ctrl.StartUrl 33 | basic.InitConfig() 34 | ctrl.Downloader = downloader.NewDownloader() 35 | ctrl.Channel = middleware.NewChannel() 36 | ctrl.WorkPool = middleware.NewWorkPool() 37 | ctrl.Parser = analyzer.NewAnalyzer() 38 | prereq, err := http.NewRequest(basic.Config.RequestMethod, basic.Config.StartUrl, nil) 39 | if err != nil { 40 | return 41 | } 42 | basereq := basic.NewRequest(prereq, 0) 43 | ctrl.Channel.ReqChan() <- *basereq 44 | wg.Add(2) 45 | go ctrl.FirstDown() 46 | go ctrl.FirstAnalyzer() 47 | wg.Wait() 48 | respshares := ctrl.Channel.RespShares() 49 | resp := <-respshares 50 | for _, ch := range resp { 51 | fmt.Println("ch:", ch) 52 | } 53 | 54 | //下载--- 55 | var wg sync.WaitGroup 56 | shchan := make(chan res.Shares, 10) 57 | 58 | wg.Add(2) 59 | go func() { 60 | defer wg.Done() 61 | for _, ch := range resp { 62 | shchan <- ch 63 | } 64 | close(shchan) 65 | }() 66 | 67 | go func() { 68 | ctrl.WorkPool.Pool(basic.Config.RequestNum, func() { 69 | for { 70 | ch, ok := <-shchan 71 | if ok == false { 72 | break 73 | } 74 | res := ctrl.DownDetail(ch) 75 | fmt.Println("res:", res) 76 | } 77 | wg.Done() 78 | }) 79 | }() 80 | 81 | wg.Wait() 82 | fmt.Println("下载结束---") 83 | } 84 | 85 | func (ctrl *Controller) FirstDown() { 86 | logger.Info("FirstDown...") 87 | defer wg.Done() 88 | dwg := new(sync.WaitGroup) 89 | dwg.Add(1) 90 | go func() { 91 | req := <-ctrl.Channel.ReqChan() 92 | res := ctrl.Downloader.Download(&req) 93 | if res != nil { 94 | ctrl.Channel.RespChan() <- *res //访问成功 95 | } 96 | dwg.Done() 97 | }() 98 | dwg.Wait() 99 | go func() {}() 100 | close(ctrl.Channel.RespChan()) 101 | } 102 | 103 | func (ctrl *Controller) FirstAnalyzer() { 104 | defer wg.Done() 105 | awg := new(sync.WaitGroup) 106 | awg.Add(1) 107 | go func() { 108 | res := <-ctrl.Channel.RespChan() 109 | resp := ctrl.Parser.AnalyzeHtml(res.GetRes()) 110 | fmt.Println("解析结果:", resp) 111 | ctrl.Channel.RespShares() <- resp 112 | awg.Done() 113 | }() 114 | awg.Wait() 115 | close(ctrl.Channel.RespShares()) 116 | } 117 | 118 | func (ctrl *Controller) DownDetail(ch res.Shares) *res.SharesRes { 119 | fmt.Println("获取:", ch) 120 | linkurl := "https://gupiao.baidu.com/api/stocks/stockdaybar?from=pc&os_ver=1&cuid=xxx&vv=100&format=json&stock_code=" + 121 | ch.GetLinkCode() + "&step=3&start=&count=160&fq_type=no×tamp=" + util.GetTimeStap() 122 | prereq, err := http.NewRequest(basic.Config.RequestMethod, linkurl, nil) 123 | if err != nil { 124 | fmt.Println("error:11", err.Error()) 125 | return nil 126 | } 127 | basereq := basic.NewRequest(prereq, 0) 128 | resp := ctrl.Downloader.Download(basereq) 129 | res := ctrl.Parser.AnalyzeApi(resp.GetRes(), ch) 130 | return res 131 | } 132 | -------------------------------------------------------------------------------- /basic/logging.go: -------------------------------------------------------------------------------- 1 | package basic 2 | // 2019.02.22 3 | import ( 4 | "fmt" 5 | "log" 6 | "runtime" 7 | "strings" 8 | ) 9 | 10 | type Position uint 11 | 12 | const ( 13 | POSITION_SINGLE Position = 1 14 | POSITION_IN_MANAGER Position = 2 15 | ) 16 | 17 | func init() { 18 | log.SetFlags(log.LstdFlags) 19 | } 20 | 21 | type Logger interface { 22 | GetPosition() Position 23 | SetPosition(pos Position) 24 | Error(v ...interface{}) string 25 | Errorf(format string, v ...interface{}) string 26 | Errorln(v ...interface{}) string 27 | Fatal(v ...interface{}) string 28 | Fatalf(format string, v ...interface{}) string 29 | Fatalln(v ...interface{}) string 30 | Info(v ...interface{}) string 31 | Infof(format string, v ...interface{}) string 32 | Infoln(v ...interface{}) string 33 | Panic(v ...interface{}) string 34 | Panicf(format string, v ...interface{}) string 35 | Panicln(v ...interface{}) string 36 | Warn(v ...interface{}) string 37 | Warnf(format string, v ...interface{}) string 38 | Warnln(v ...interface{}) string 39 | } 40 | 41 | func getInvokerLocation(skipNumber int) string { 42 | pc, file, line, ok := runtime.Caller(skipNumber) 43 | if !ok { 44 | return "" 45 | } 46 | simpleFileName := "" 47 | if index := strings.LastIndex(file, "/"); index > 0 { 48 | simpleFileName = file[index+1 : len(file)] 49 | } 50 | funcPath := "" 51 | funcPtr := runtime.FuncForPC(pc) 52 | if funcPtr != nil { 53 | funcPath = funcPtr.Name() 54 | } 55 | return fmt.Sprintf("%s : (%s:%d)", funcPath, simpleFileName, line) 56 | } 57 | 58 | func generateLogContent( 59 | logTag LogTag, 60 | pos Position, 61 | format string, 62 | v ...interface{}) string { 63 | skipNumber := int(pos) + 2 64 | baseInfo := 65 | fmt.Sprintf("%s %s - ", logTag.Prefix(), getInvokerLocation(skipNumber)) 66 | var result string 67 | if len(format) > 0 { 68 | result = fmt.Sprintf((baseInfo + format), v...) 69 | } else { 70 | vLen := len(v) 71 | params := make([]interface{}, (vLen + 1)) 72 | params[0] = baseInfo 73 | for i := 1; i <= vLen; i++ { 74 | params[i] = v[i-1] 75 | } 76 | result = fmt.Sprint(params...) 77 | } 78 | return result 79 | } 80 | 81 | func NewSimpleLogger() Logger { 82 | logger := &ConsoleLogger{} 83 | logger.SetPosition(POSITION_SINGLE) 84 | return logger 85 | } 86 | 87 | func NewLogger(loggers []Logger) Logger { 88 | for _, logger := range loggers { 89 | logger.SetPosition(POSITION_IN_MANAGER) 90 | } 91 | return &LogManager{loggers: loggers} 92 | } 93 | 94 | type ConsoleLogger struct { 95 | position Position 96 | } 97 | 98 | func (logger *ConsoleLogger) GetPosition() Position { 99 | return logger.position 100 | } 101 | 102 | func (logger *ConsoleLogger) SetPosition(pos Position) { 103 | logger.position = pos 104 | } 105 | 106 | func (logger *ConsoleLogger) Error(v ...interface{}) string { 107 | content := generateLogContent(getErrorLogTag(), logger.GetPosition(), "", v...) 108 | log.Print(content) 109 | return content 110 | } 111 | 112 | func (logger *ConsoleLogger) Errorf(format string, v ...interface{}) string { 113 | content := generateLogContent(getErrorLogTag(), logger.GetPosition(), format, v...) 114 | log.Print(content) 115 | return content 116 | } 117 | 118 | func (logger *ConsoleLogger) Errorln(v ...interface{}) string { 119 | content := generateLogContent(getErrorLogTag(), logger.GetPosition(), "", v...) 120 | log.Println(content) 121 | return content 122 | } 123 | 124 | func (logger *ConsoleLogger) Fatal(v ...interface{}) string { 125 | content := generateLogContent(getFatalLogTag(), logger.GetPosition(), "", v...) 126 | log.Print(content) 127 | return content 128 | } 129 | 130 | func (logger *ConsoleLogger) Fatalf(format string, v ...interface{}) string { 131 | content := generateLogContent(getFatalLogTag(), logger.GetPosition(), format, v...) 132 | log.Print(content) 133 | return content 134 | } 135 | 136 | func (logger *ConsoleLogger) Fatalln(v ...interface{}) string { 137 | content := generateLogContent(getFatalLogTag(), logger.GetPosition(), "", v...) 138 | log.Println(content) 139 | return content 140 | } 141 | 142 | func (logger *ConsoleLogger) Info(v ...interface{}) string { 143 | content := generateLogContent(getInfoLogTag(), logger.GetPosition(), "", v...) 144 | log.Print(content) 145 | return content 146 | } 147 | 148 | func (logger *ConsoleLogger) Infof(format string, v ...interface{}) string { 149 | content := generateLogContent(getInfoLogTag(), logger.GetPosition(), format, v...) 150 | log.Print(content) 151 | return content 152 | } 153 | 154 | func (logger *ConsoleLogger) Infoln(v ...interface{}) string { 155 | content := generateLogContent(getInfoLogTag(), logger.GetPosition(), "", v...) 156 | log.Println(content) 157 | return content 158 | } 159 | 160 | func (logger *ConsoleLogger) Panic(v ...interface{}) string { 161 | content := generateLogContent(getPanicLogTag(), logger.GetPosition(), "", v...) 162 | log.Print(content) 163 | return content 164 | } 165 | 166 | func (logger *ConsoleLogger) Panicf(format string, v ...interface{}) string { 167 | content := generateLogContent(getPanicLogTag(), logger.GetPosition(), format, v...) 168 | log.Print(content) 169 | return content 170 | } 171 | 172 | func (logger *ConsoleLogger) Panicln(v ...interface{}) string { 173 | content := generateLogContent(getPanicLogTag(), logger.GetPosition(), "", v...) 174 | log.Println(content) 175 | return content 176 | } 177 | 178 | func (logger *ConsoleLogger) Warn(v ...interface{}) string { 179 | content := generateLogContent(getWarnLogTag(), logger.GetPosition(), "", v...) 180 | log.Print(content) 181 | return content 182 | } 183 | 184 | func (logger *ConsoleLogger) Warnf(format string, v ...interface{}) string { 185 | content := generateLogContent(getWarnLogTag(), logger.GetPosition(), format, v...) 186 | log.Print(content) 187 | return content 188 | } 189 | 190 | func (logger *ConsoleLogger) Warnln(v ...interface{}) string { 191 | content := generateLogContent(getWarnLogTag(), logger.GetPosition(), "", v...) 192 | log.Println(content) 193 | return content 194 | } 195 | 196 | type LogManager struct { 197 | loggers []Logger 198 | } 199 | 200 | func (logger *LogManager) GetPosition() Position { 201 | return POSITION_SINGLE 202 | } 203 | 204 | func (logger *LogManager) SetPosition(pos Position) {} 205 | 206 | func (self *LogManager) Error(v ...interface{}) string { 207 | var content string 208 | for _, logger := range self.loggers { 209 | content = logger.Error(v...) 210 | } 211 | return content 212 | } 213 | 214 | func (self *LogManager) Errorf(format string, v ...interface{}) string { 215 | var content string 216 | for _, logger := range self.loggers { 217 | content = logger.Errorf(format, v...) 218 | } 219 | return content 220 | } 221 | 222 | func (self *LogManager) Errorln(v ...interface{}) string { 223 | var content string 224 | for _, logger := range self.loggers { 225 | content = logger.Errorln(v...) 226 | } 227 | return content 228 | } 229 | 230 | func (self *LogManager) Fatal(v ...interface{}) string { 231 | var content string 232 | for _, logger := range self.loggers { 233 | content = logger.Fatal(v...) 234 | } 235 | return content 236 | } 237 | 238 | func (self *LogManager) Fatalf(format string, v ...interface{}) string { 239 | var content string 240 | for _, logger := range self.loggers { 241 | content = logger.Fatalf(format, v...) 242 | } 243 | return content 244 | } 245 | 246 | func (self *LogManager) Fatalln(v ...interface{}) string { 247 | var content string 248 | for _, logger := range self.loggers { 249 | content = logger.Fatalln(v...) 250 | } 251 | return content 252 | } 253 | 254 | func (self *LogManager) Info(v ...interface{}) string { 255 | var content string 256 | for _, logger := range self.loggers { 257 | content = logger.Info(v...) 258 | } 259 | return content 260 | } 261 | 262 | func (self *LogManager) Infof(format string, v ...interface{}) string { 263 | var content string 264 | for _, logger := range self.loggers { 265 | content = logger.Infof(format, v...) 266 | } 267 | return content 268 | } 269 | 270 | func (self *LogManager) Infoln(v ...interface{}) string { 271 | var content string 272 | for _, logger := range self.loggers { 273 | content = logger.Infoln(v...) 274 | } 275 | return content 276 | } 277 | 278 | func (self *LogManager) Panic(v ...interface{}) string { 279 | var content string 280 | for _, logger := range self.loggers { 281 | content = logger.Panic(v...) 282 | } 283 | return content 284 | } 285 | 286 | func (self *LogManager) Panicf(format string, v ...interface{}) string { 287 | var content string 288 | for _, logger := range self.loggers { 289 | content = logger.Panicf(format, v...) 290 | } 291 | return content 292 | } 293 | 294 | func (self *LogManager) Panicln(v ...interface{}) string { 295 | var content string 296 | for _, logger := range self.loggers { 297 | content = logger.Panicln(v...) 298 | } 299 | return content 300 | } 301 | 302 | func (self *LogManager) Warn(v ...interface{}) string { 303 | var content string 304 | for _, logger := range self.loggers { 305 | content = logger.Warn(v...) 306 | } 307 | return content 308 | } 309 | 310 | func (self *LogManager) Warnf(format string, v ...interface{}) string { 311 | var content string 312 | for _, logger := range self.loggers { 313 | content = logger.Warnf(format, v...) 314 | } 315 | return content 316 | } 317 | 318 | func (self *LogManager) Warnln(v ...interface{}) string { 319 | var content string 320 | for _, logger := range self.loggers { 321 | content = logger.Warnln(v...) 322 | } 323 | return content 324 | } 325 | 326 | const ( 327 | ERROR_LOG_KEY = "ERROR" 328 | FATAL_LOG_KEY = "FATAL" 329 | INFO_LOG_KEY = "INFO" 330 | PANIC_LOG_KEY = "PANIC" 331 | WARN_LOG_KEY = "WARN" 332 | ) 333 | 334 | type LogTag struct { 335 | name string 336 | prefix string 337 | } 338 | 339 | func (self *LogTag) Name() string { 340 | return self.name 341 | } 342 | 343 | func (self *LogTag) Prefix() string { 344 | return self.prefix 345 | } 346 | 347 | var logTagMap map[string]LogTag = map[string]LogTag{ 348 | ERROR_LOG_KEY: LogTag{name: ERROR_LOG_KEY, prefix: "[" + ERROR_LOG_KEY + "]"}, 349 | FATAL_LOG_KEY: LogTag{name: FATAL_LOG_KEY, prefix: "[" + FATAL_LOG_KEY + "]"}, 350 | INFO_LOG_KEY: LogTag{name: INFO_LOG_KEY, prefix: "[" + INFO_LOG_KEY + "]"}, 351 | PANIC_LOG_KEY: LogTag{name: PANIC_LOG_KEY, prefix: "[" + PANIC_LOG_KEY + "]"}, 352 | WARN_LOG_KEY: LogTag{name: WARN_LOG_KEY, prefix: "[" + WARN_LOG_KEY + "]"}, 353 | } 354 | 355 | func getErrorLogTag() LogTag { 356 | return logTagMap[ERROR_LOG_KEY] 357 | } 358 | 359 | func getFatalLogTag() LogTag { 360 | return logTagMap[FATAL_LOG_KEY] 361 | } 362 | 363 | func getInfoLogTag() LogTag { 364 | return logTagMap[INFO_LOG_KEY] 365 | } 366 | 367 | func getPanicLogTag() LogTag { 368 | return logTagMap[PANIC_LOG_KEY] 369 | } 370 | 371 | func getWarnLogTag() LogTag { 372 | return logTagMap[WARN_LOG_KEY] 373 | } 374 | --------------------------------------------------------------------------------