|
@@ -1,574 +0,0 @@
|
|
-package util
|
|
|
|
-
|
|
|
|
-import (
|
|
|
|
- "encoding/json"
|
|
|
|
- "errors"
|
|
|
|
- "log"
|
|
|
|
- "runtime"
|
|
|
|
- "strings"
|
|
|
|
- "time"
|
|
|
|
-
|
|
|
|
- redigo "github.com/garyburd/redigo/redis"
|
|
|
|
-)
|
|
|
|
-
|
|
|
|
-var RedisPool = make(map[string]*redigo.Pool, 0)
|
|
|
|
-func InitRedisPool(modules, address string, maxPoolSize, maxPoolIdle, idleTimeOut int) error {
|
|
|
|
- var e error
|
|
|
|
- if !IsEmpty(modules) && !IsEmpty(address) {
|
|
|
|
- a := strings.Split(address, ",")
|
|
|
|
- m := strings.Split(modules, ",")
|
|
|
|
- if len(a) == len(m) {
|
|
|
|
- for i, val := range a {
|
|
|
|
- e = InitModuleRedis(val, m[i], maxPoolSize, maxPoolIdle, idleTimeOut)
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return e
|
|
|
|
-}
|
|
|
|
-func IsEmpty(str string) bool {
|
|
|
|
- if strings.TrimSpace(str) == "" {
|
|
|
|
- return true
|
|
|
|
- }
|
|
|
|
- return false
|
|
|
|
-}
|
|
|
|
-func InitModuleRedis(addr string, module string, maxSize, maxIdle, timeout int) error {
|
|
|
|
- var e error
|
|
|
|
- RedisPool[module] = &redigo.Pool{
|
|
|
|
- MaxActive: maxSize,
|
|
|
|
- MaxIdle: maxIdle,
|
|
|
|
- IdleTimeout: time.Duration(timeout) * time.Second,
|
|
|
|
- Dial: func() (redigo.Conn, error) {
|
|
|
|
- c, err := redigo.Dial("tcp", addr)
|
|
|
|
- if err != nil {
|
|
|
|
- log.Printf("redis addr:[%s],module:[%s] dial error:[%v]", addr, err)
|
|
|
|
- e = err
|
|
|
|
- return nil, err
|
|
|
|
- }
|
|
|
|
- return c, nil
|
|
|
|
- }}
|
|
|
|
- return e
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/*func InitRedisBySize(addrs string, maxSize, maxIdle, timeout int) {
|
|
|
|
- RedisPool = map[string]*redigo.Pool{}
|
|
|
|
- addr := strings.Split(addrs, ",")
|
|
|
|
- for _, v := range addr {
|
|
|
|
- saddr := strings.Split(v, "=")
|
|
|
|
- RedisPool[saddr[0]] = &redigo.Pool{MaxActive: maxSize, MaxIdle: maxIdle,
|
|
|
|
- IdleTimeout: time.Duration(timeout) * time.Second, Dial: func() (redigo.Conn, error) {
|
|
|
|
- c, err := redigo.Dial("tcp", saddr[1])
|
|
|
|
- if err != nil {
|
|
|
|
- return nil, err
|
|
|
|
- }
|
|
|
|
- return c, nil
|
|
|
|
- }}
|
|
|
|
- }
|
|
|
|
-}*/
|
|
|
|
-
|
|
|
|
-//分流redis
|
|
|
|
-//并存入字符串缓存
|
|
|
|
-func PutKV(key string, obj interface{}) bool {
|
|
|
|
- return Put("other", key, obj, -1)
|
|
|
|
-}
|
|
|
|
-func PutCKV(code, key string, obj interface{}) bool {
|
|
|
|
- return Put(code, key, obj, -1)
|
|
|
|
-}
|
|
|
|
-func Put(code, key string, obj interface{}, timeout int) bool {
|
|
|
|
- b := false
|
|
|
|
- defer catch()
|
|
|
|
- conn := RedisPool[code].Get()
|
|
|
|
- defer conn.Close()
|
|
|
|
- var err error
|
|
|
|
- _obj, _err := json.Marshal(obj)
|
|
|
|
- if _err != nil {
|
|
|
|
- log.Println("redisutil-SET-序列化出错Error", _err)
|
|
|
|
- return b
|
|
|
|
- }
|
|
|
|
- if timeout < 1 {
|
|
|
|
- _, err = conn.Do("SET", key, _obj)
|
|
|
|
- } else {
|
|
|
|
- _, err = conn.Do("SET", key, _obj, "EX", timeout)
|
|
|
|
- }
|
|
|
|
- if nil != err {
|
|
|
|
- log.Println("redisutil-SETError-put", err)
|
|
|
|
- } else {
|
|
|
|
- b = true
|
|
|
|
- }
|
|
|
|
- return b
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-func BulkPut(code string, timeout int, obj ...interface{}) bool {
|
|
|
|
- b := false
|
|
|
|
- defer catch()
|
|
|
|
- conn := RedisPool[code].Get()
|
|
|
|
- defer conn.Close()
|
|
|
|
- var err error
|
|
|
|
- for _, _tmp := range obj {
|
|
|
|
- tmp, ok := _tmp.([]interface{})
|
|
|
|
- if ok && len(tmp) == 2 {
|
|
|
|
- key, kok := tmp[0].(string)
|
|
|
|
- if kok && key != "" {
|
|
|
|
- _obj, _err := json.Marshal(tmp[1])
|
|
|
|
- if _err != nil {
|
|
|
|
- log.Println("redisutil-SET-序列化出错Error", _err)
|
|
|
|
- return b
|
|
|
|
- }
|
|
|
|
- if timeout < 1 {
|
|
|
|
- _, err = conn.Do("SET", key, _obj)
|
|
|
|
- } else {
|
|
|
|
- _, err = conn.Do("SET", key, _obj, "EX", timeout)
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- if nil != err {
|
|
|
|
- b = false
|
|
|
|
- log.Println("redisutil-SETError-put", err)
|
|
|
|
- } else {
|
|
|
|
- b = b && true
|
|
|
|
- }
|
|
|
|
- return b
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-//直接存字节流
|
|
|
|
-func PutBytes(code, key string, data *[]byte, timeout int) (err error) {
|
|
|
|
- defer catch()
|
|
|
|
-
|
|
|
|
- conn := RedisPool[code].Get()
|
|
|
|
- defer conn.Close()
|
|
|
|
-
|
|
|
|
- if timeout < 1 {
|
|
|
|
- _, err = conn.Do("SET", key, *data)
|
|
|
|
- } else {
|
|
|
|
- _, err = conn.Do("SET", key, *data, "EX", timeout)
|
|
|
|
- }
|
|
|
|
- if nil != err {
|
|
|
|
- log.Println("redisutil-SETError", err)
|
|
|
|
- }
|
|
|
|
- return
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-//设置超时时间,单位秒
|
|
|
|
-func SetExpire(code, key string, expire int) error {
|
|
|
|
- defer catch()
|
|
|
|
- conn := RedisPool[code].Get()
|
|
|
|
- defer conn.Close()
|
|
|
|
- _, err := conn.Do("expire", key, expire)
|
|
|
|
- return err
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-//判断一个key是否存在
|
|
|
|
-func Exists(code, key string) (bool, error) {
|
|
|
|
- defer catch()
|
|
|
|
-
|
|
|
|
- conn := RedisPool[code].Get()
|
|
|
|
- defer conn.Close()
|
|
|
|
- repl, err := conn.Do("exists", key)
|
|
|
|
- ret, _ := redigo.Int(repl, err)
|
|
|
|
- return ret == 1, err
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-//获取string
|
|
|
|
-func GetStr(code, key string) string {
|
|
|
|
- res := Get(code, key)
|
|
|
|
- str, _ := res.(string)
|
|
|
|
- return str
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-//获取int
|
|
|
|
-func GetInt(code, key string) int {
|
|
|
|
- res := Get(code, key)
|
|
|
|
- var result int
|
|
|
|
- if str, ok := res.(float64); ok {
|
|
|
|
- result = int(str)
|
|
|
|
- }
|
|
|
|
- return result
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-//取得字符串,支持变参,2个 (key,code),返回后自己断言
|
|
|
|
-func Get(code, key string) (result interface{}) {
|
|
|
|
- GetInterface(code, key, &result)
|
|
|
|
- return
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-func GetInterface(code, key string, result interface{}) {
|
|
|
|
- defer catch()
|
|
|
|
-
|
|
|
|
- conn := RedisPool[code].Get()
|
|
|
|
- defer conn.Close()
|
|
|
|
- ret, err := conn.Do("GET", key)
|
|
|
|
- if nil != err {
|
|
|
|
- log.Println("redisutil-GetError", err)
|
|
|
|
- } else {
|
|
|
|
- var ok bool
|
|
|
|
- var res []byte
|
|
|
|
- if res, ok = ret.([]byte); ok {
|
|
|
|
- err = json.Unmarshal(res, result)
|
|
|
|
- if err != nil {
|
|
|
|
- log.Println("Get ERROR:", err.Error())
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-//增加多少数据
|
|
|
|
-func Incrby(code, key string, val int) int64 {
|
|
|
|
- defer catch()
|
|
|
|
- conn := RedisPool[code].Get()
|
|
|
|
- defer conn.Close()
|
|
|
|
- ret, err := conn.Do("INCRBY", key, val)
|
|
|
|
- if nil != err {
|
|
|
|
- log.Println("redisutil-INCRBY-Error", err)
|
|
|
|
- } else {
|
|
|
|
- if res, ok := ret.(int64); ok {
|
|
|
|
- return res
|
|
|
|
- } else {
|
|
|
|
- return 0
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return 0
|
|
|
|
-}
|
|
|
|
-//自减(带限制的)
|
|
|
|
-func DecrbyLimit(code, key string, val int, limit int64) bool {
|
|
|
|
- defer catch()
|
|
|
|
- conn := RedisPool[code].Get()
|
|
|
|
- defer conn.Close()
|
|
|
|
- ret, err := conn.Do("DECRBY", key, val)
|
|
|
|
- if nil != err {
|
|
|
|
- log.Println("redisutil-DECR-Error", err)
|
|
|
|
- return false
|
|
|
|
- } else {
|
|
|
|
- if res, ok := ret.(int64); ok {
|
|
|
|
- if res < limit {
|
|
|
|
- Incrby(code, key, val)
|
|
|
|
- return false
|
|
|
|
- }
|
|
|
|
- return true
|
|
|
|
- } else {
|
|
|
|
- return false
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-//直接返回字节流
|
|
|
|
-func GetBytes(code, key string) (ret *[]byte, err error) {
|
|
|
|
- defer catch()
|
|
|
|
-
|
|
|
|
- conn := RedisPool[code].Get()
|
|
|
|
- defer conn.Close()
|
|
|
|
- var r interface{}
|
|
|
|
- r, err = conn.Do("GET", key)
|
|
|
|
- if err != nil {
|
|
|
|
- log.Println("redisutil-GetBytesError", err)
|
|
|
|
- } else {
|
|
|
|
- if tmp, ok := r.([]byte); ok {
|
|
|
|
- ret = &tmp
|
|
|
|
- } else {
|
|
|
|
- err = errors.New("redis返回数据格式不对")
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return
|
|
|
|
-}
|
|
|
|
-func GetNewBytes(code, key string) (ret *[]byte, err error) {
|
|
|
|
- defer catch()
|
|
|
|
- redisPool := RedisPool[code]
|
|
|
|
- if redisPool == nil {
|
|
|
|
- err = errors.New("redis code " + code + " is nil")
|
|
|
|
- log.Println("redisutil-GetNewBytesError", err)
|
|
|
|
- return
|
|
|
|
- }
|
|
|
|
- conn := redisPool.Get()
|
|
|
|
- defer conn.Close()
|
|
|
|
- var r interface{}
|
|
|
|
- r, err = conn.Do("GET", key)
|
|
|
|
- if err != nil {
|
|
|
|
- log.Println("redisutil-GetNewBytesError", err)
|
|
|
|
- } else if r != nil {
|
|
|
|
- if tmp, ok := r.([]byte); ok {
|
|
|
|
- ret = &tmp
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-//删所有key
|
|
|
|
-func FlushDB(code string) bool {
|
|
|
|
- b := false
|
|
|
|
- defer catch()
|
|
|
|
-
|
|
|
|
- conn := RedisPool[code].Get()
|
|
|
|
- defer conn.Close()
|
|
|
|
-
|
|
|
|
- var err error
|
|
|
|
- _, err = conn.Do("FLUSHDB")
|
|
|
|
- if nil != err {
|
|
|
|
- log.Println("redisutil-FLUSHDBError", err)
|
|
|
|
- } else {
|
|
|
|
- b = true
|
|
|
|
- }
|
|
|
|
- return b
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-//支持删除多个key
|
|
|
|
-func Del(code string, key ...interface{}) bool {
|
|
|
|
- defer catch()
|
|
|
|
- b := false
|
|
|
|
- conn := RedisPool[code].Get()
|
|
|
|
- defer conn.Close()
|
|
|
|
-
|
|
|
|
- var err error
|
|
|
|
- _, err = conn.Do("DEL", key...)
|
|
|
|
- if nil != err {
|
|
|
|
- log.Println("redisutil-DELError", err)
|
|
|
|
- } else {
|
|
|
|
- b = true
|
|
|
|
- }
|
|
|
|
- return b
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/**
|
|
|
|
-func DelKey(key ...interface{}) {
|
|
|
|
- defer func() {
|
|
|
|
- if r := recover(); r != nil {
|
|
|
|
- log.Println("[E]", r)
|
|
|
|
- for skip := 1; ; skip++ {
|
|
|
|
- _, file, line, ok := runtime.Caller(skip)
|
|
|
|
- if !ok {
|
|
|
|
- break
|
|
|
|
- }
|
|
|
|
- go log.Printf("%v,%v\n", file, line)
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }()
|
|
|
|
- for i := 0; i < len(RedisPool); i++ {
|
|
|
|
- delByNum(i, key...)
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-}
|
|
|
|
-**/
|
|
|
|
-
|
|
|
|
-/**
|
|
|
|
-func delByNum(n int, key ...interface{}) {
|
|
|
|
- defer func() {
|
|
|
|
- if r := recover(); r != nil {
|
|
|
|
- log.Println("[E]", r)
|
|
|
|
- for skip := 1; ; skip++ {
|
|
|
|
- _, file, line, ok := runtime.Caller(skip)
|
|
|
|
- if !ok {
|
|
|
|
- break
|
|
|
|
- }
|
|
|
|
- go log.Printf("%v,%v\n", file, line)
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }()
|
|
|
|
- i := 0
|
|
|
|
- for _, v := range RedisPool {
|
|
|
|
- if i == n {
|
|
|
|
- conn := v.Get()
|
|
|
|
- defer conn.Close()
|
|
|
|
- conn.Do("DEL", key...)
|
|
|
|
- break
|
|
|
|
- }
|
|
|
|
- i++
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-//根据代码和前辍key删除多个
|
|
|
|
-func DelByCodePattern(code, key string) {
|
|
|
|
- defer catch()
|
|
|
|
-
|
|
|
|
- conn := RedisPool[code].Get()
|
|
|
|
- defer conn.Close()
|
|
|
|
- ret, err := conn.Do("KEYS", key)
|
|
|
|
- var result []interface{}
|
|
|
|
- if nil != err {
|
|
|
|
- log.Println("redisutil-GetError", err)
|
|
|
|
- } else {
|
|
|
|
- result = ret.([]interface{})
|
|
|
|
- for k := 0; k < len(result); k++ {
|
|
|
|
- conn.Do("DEL", string(result[k].([]uint8)))
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/**
|
|
|
|
-func DelByPattern(key string) {
|
|
|
|
- defer func() {
|
|
|
|
- if r := recover(); r != nil {
|
|
|
|
- log.Println("[E]", r)
|
|
|
|
- for skip := 1; ; skip++ {
|
|
|
|
- _, file, line, ok := runtime.Caller(skip)
|
|
|
|
- if !ok {
|
|
|
|
- break
|
|
|
|
- }
|
|
|
|
- go log.Printf("%v,%v\n", file, line)
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }()
|
|
|
|
- i := 0
|
|
|
|
- for _, v := range RedisPool {
|
|
|
|
- conn := v.Get()
|
|
|
|
- defer conn.Close()
|
|
|
|
- ret, err := conn.Do("KEYS", key)
|
|
|
|
- var result []interface{}
|
|
|
|
- if nil != err {
|
|
|
|
- log.Println("redisutil-GetError", err)
|
|
|
|
- } else {
|
|
|
|
- result = ret.([]interface{})
|
|
|
|
- for k := 0; k < len(result); k++ {
|
|
|
|
- delByNum(i, string(result[k].([]uint8)))
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- i++
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-}
|
|
|
|
-**/
|
|
|
|
-//自增计数器
|
|
|
|
-func Incr(code, key string) int64 {
|
|
|
|
- defer catch()
|
|
|
|
- conn := RedisPool[code].Get()
|
|
|
|
- defer conn.Close()
|
|
|
|
- ret, err := conn.Do("INCR", key)
|
|
|
|
- if nil != err {
|
|
|
|
- log.Println("redisutil-INCR-Error", err)
|
|
|
|
- } else {
|
|
|
|
- if res, ok := ret.(int64); ok {
|
|
|
|
- return res
|
|
|
|
- } else {
|
|
|
|
- return 0
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return 0
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-//自减
|
|
|
|
-func Decrby(code, key string, val int) int64 {
|
|
|
|
- defer catch()
|
|
|
|
- conn := RedisPool[code].Get()
|
|
|
|
- defer conn.Close()
|
|
|
|
- ret, err := conn.Do("DECRBY", key, val)
|
|
|
|
- if nil != err {
|
|
|
|
- log.Println("redisutil-DECR-Error", err)
|
|
|
|
- } else {
|
|
|
|
- if res, ok := ret.(int64); ok {
|
|
|
|
- return res
|
|
|
|
- } else {
|
|
|
|
- return 0
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return 0
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-//根据正则去取
|
|
|
|
-func GetKeysByPattern(code, key string) []interface{} {
|
|
|
|
- defer catch()
|
|
|
|
- conn := RedisPool[code].Get()
|
|
|
|
- defer conn.Close()
|
|
|
|
- ret, err := conn.Do("KEYS", key)
|
|
|
|
- if nil != err {
|
|
|
|
- log.Println("redisutil-GetKeysError", err)
|
|
|
|
- return nil
|
|
|
|
- } else {
|
|
|
|
- res, _ := ret.([]interface{})
|
|
|
|
- return res
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-//批量取多个key
|
|
|
|
-func Mget(code string, key []string) []interface{} {
|
|
|
|
- defer catch()
|
|
|
|
- conn := RedisPool[code].Get()
|
|
|
|
- defer conn.Close()
|
|
|
|
- interfaceKeys := make([]interface{}, len(key))
|
|
|
|
- for n, k := range key {
|
|
|
|
- interfaceKeys[n] = k
|
|
|
|
- }
|
|
|
|
- ret, err := conn.Do("MGET", interfaceKeys...)
|
|
|
|
- if nil != err {
|
|
|
|
- log.Println("redisutil-MgetError", err)
|
|
|
|
- return nil
|
|
|
|
- } else {
|
|
|
|
- res, _ := ret.([]interface{})
|
|
|
|
- return res
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-//取出并删除Key
|
|
|
|
-func Pop(code string, key string) (result interface{}) {
|
|
|
|
- defer catch()
|
|
|
|
- conn := RedisPool[code].Get()
|
|
|
|
- defer conn.Close()
|
|
|
|
- ret, err := conn.Do("GET", key)
|
|
|
|
- if nil != err {
|
|
|
|
- log.Println("redisutil-PopError", err)
|
|
|
|
- } else {
|
|
|
|
- var ok bool
|
|
|
|
- var res []byte
|
|
|
|
- if res, ok = ret.([]byte); ok {
|
|
|
|
- err = json.Unmarshal(res, &result)
|
|
|
|
- if err != nil {
|
|
|
|
- log.Println("Poperr", err)
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- conn.Do("DEL", key)
|
|
|
|
- }
|
|
|
|
- return
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-//list操作
|
|
|
|
-func LPOP(code, list string) (result interface{}) {
|
|
|
|
- defer catch()
|
|
|
|
- conn := RedisPool[code].Get()
|
|
|
|
- defer conn.Close()
|
|
|
|
- ret, err := conn.Do("LPOP", list)
|
|
|
|
- if nil != err {
|
|
|
|
- log.Println("redisutil-LPopError", err)
|
|
|
|
- } else {
|
|
|
|
- if res, ok := ret.([]byte); ok {
|
|
|
|
- err = json.Unmarshal(res, &result)
|
|
|
|
- log.Println(err)
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-func RPUSH(code, list string, val interface{}) bool {
|
|
|
|
- defer catch()
|
|
|
|
- conn := RedisPool[code].Get()
|
|
|
|
- defer conn.Close()
|
|
|
|
- _obj, _ := json.Marshal(val)
|
|
|
|
- _, err := conn.Do("RPUSH", list, _obj)
|
|
|
|
- if nil != err {
|
|
|
|
- log.Println("redisutil-RPUSHError", err)
|
|
|
|
- return false
|
|
|
|
- }
|
|
|
|
- return true
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-func LLEN(code, list string) int64 {
|
|
|
|
- defer catch()
|
|
|
|
- conn := RedisPool[code].Get()
|
|
|
|
- defer conn.Close()
|
|
|
|
- ret, err := conn.Do("LLEN", list)
|
|
|
|
- if nil != err {
|
|
|
|
- log.Println("redisutil-LLENError", err)
|
|
|
|
- return 0
|
|
|
|
- }
|
|
|
|
- if res, ok := ret.(int64); ok {
|
|
|
|
- return res
|
|
|
|
- } else {
|
|
|
|
- return 0
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-func catch() {
|
|
|
|
- if r := recover(); r != nil {
|
|
|
|
- log.Println(r)
|
|
|
|
- for skip := 0; ; skip++ {
|
|
|
|
- _, file, line, ok := runtime.Caller(skip)
|
|
|
|
- if !ok {
|
|
|
|
- break
|
|
|
|
- }
|
|
|
|
- go log.Printf("%v,%v\n", file, line)
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|