Пример #1
0
Файл: log.go Проект: unikk/cuto
// ロガーの初期化処理を行う
//
// param ; dir       ログファイルの出力先ディレクトリ。
//
// param : name      ログファイルの種別(例:master、servant)。
//
// param : identifer ロック用ファイルに(付与する識別ID(例:servantはListePort)。
//
// param : level     出力ログレベル(trace,debug,info,warn,error,criticalのいずれかを指定)
//
// param : maxSizeKB ログファイルの最大サイズ。この値を超えるとログローテーションが発生する。
//
// param : maxRolls  ログファイルの最大世代数
//
// param : timeoutSec  ロックのタイムアウト秒
//
// return : エラー情報を返す。
func Init(dir string, name string, identifer string, level string, maxSizeKB int, maxRolls int, timeoutSec int) error {
	var lockErr error
	lockName := lockHeader + name
	if identifer != "" {
		lockName = lockName + "_" + identifer
	}
	lockName = lockName + ".lock"
	locker, lockErr = util.InitLock(lockName)
	if lockErr != nil {
		return lockErr
	}
	if timeoutSec > 0 {
		lockTimeout = timeoutSec * 1000
	}

	logfile := fmt.Sprintf("%s%c%s.log", dir, os.PathSeparator, name)
	if err := makeFileIfNotExist(logfile); err != nil {
		Term()
		return err
	}

	config := generateConfigString(logfile, level, maxSizeKB, maxRolls)
	logger, err := seelog.LoggerFromConfigAsString(config)
	if err != nil {
		Term()
		return err
	}

	seelog.ReplaceLogger(logger)
	valid = true

	return nil
}
Пример #2
0
func setInitLogging(logLevel string) {

	logLevel = strings.ToLower(logLevel)

	testConfig := `
	<seelog  type="sync" minlevel="`
	testConfig = testConfig + logLevel
	testConfig = testConfig + `">
		<outputs formatid="main">
			<filter levels="error">
				<file path="./log/gopa.log"/>
			</filter>
			<console formatid="main" />
		</outputs>
		<formats>
			<format id="main" format="[%Date(01-02) %Time] [%LEV] [%File:%Line,%FuncShort] %Msg%n"/>
		</formats>
	</seelog>`

	logger, err := log.LoggerFromConfigAsString(testConfig)
	if err != nil {
		log.Error("init config error,", err)
	}
	err = log.ReplaceLogger(logger)
	if err != nil {
		log.Error("init config error,", err)
	}
}
Пример #3
0
func configureLogging(verbose bool) {
	minLevel := "info"

	if verbose {
		minLevel = "trace"
	}

	logger, err := log.LoggerFromConfigAsString(fmt.Sprintf(`
<seelog minlevel="%s">
    <outputs formatid="out">
        <console />
    </outputs>

    <formats>
        <format id="out" format="%%Date %%Time [%%LEVEL] %%Msg%%n" />
    </formats>
</seelog>
`, minLevel))

	if err != nil {
		panic(err)
	}

	log.ReplaceLogger(logger)
}
Пример #4
0
func main() {
	defer log.Flush()
	flag.Parse()
	args := flag.Args()

	if len(args) == 0 {
		usage(actions(nil))
		os.Exit(1)
	}

	logger, err := log.LoggerFromConfigAsString(config.Logger())
	if err != nil {
		die(err)
	}
	log.ReplaceLogger(logger)

	init, err := engine.New()
	if err != nil {
		die(err)
	}
	log.Info(args[0])
	actions := actions(init)
	action, ok := actions[args[0]]
	if !ok {
		usage(actions)
		os.Exit(1)
	}
	err = action.function()
	if err != nil {
		die(err)
	}
}
Пример #5
0
func InitDefaultSyncLogConfig() {
	logger, err := log.LoggerFromConfigAsString(DEFAULT_SYNC_LOG_CONFIG)
	if err != nil {
		panic(err)
	}
	log.ReplaceLogger(logger)
}
Пример #6
0
func DisableLogs() {
	logger, err := log.LoggerFromConfigAsString(DEFAULT_DISABLE_LOGS_CONFIG)
	if err != nil {
		panic(err)
	}
	log.ReplaceLogger(logger)
}
Пример #7
0
// ServeHttp serves IAM Role Credentials for Tasks being managed by the agent.
func ServeHttp(credentialsManager credentials.Manager, containerInstanceArn string, cfg *config.Config) {
	// Create and initialize the audit log
	// TODO Use seelog's programmatic configuration instead of xml.
	logger, err := log.LoggerFromConfigAsString(audit.AuditLoggerConfig(cfg))
	if err != nil {
		log.Errorf("Error initializing the audit log: %v", err)
		// If the logger cannot be initialized, use the provided dummy seelog.LoggerInterface, seelog.Disabled.
		logger = log.Disabled
	}

	auditLogger := audit.NewAuditLog(containerInstanceArn, cfg, logger)

	server := setupServer(credentialsManager, auditLogger)

	for {
		utils.RetryWithBackoff(utils.NewSimpleBackoff(time.Second, time.Minute, 0.2, 2), func() error {
			// TODO, make this cancellable and use the passed in context;
			err := server.ListenAndServe()
			if err != nil {
				log.Errorf("Error running http api: %v", err)
			}
			return err
		})
	}
}
Пример #8
0
func SetupLogger() {
	logger, err := log.LoggerFromConfigAsString(loggerConfig())
	if err == nil {
		log.ReplaceLogger(logger)
	} else {
		log.Error(err)
	}
}
Пример #9
0
func reloadLogConfig() {
	logger, err := seelog.LoggerFromConfigAsString(loggerConfig())

	if err == nil {
		seelog.ReplaceLogger(logger)
	} else {
		seelog.Error(err)
	}
}
Пример #10
0
func init() {
	logger, err := log.LoggerFromConfigAsString(logConfig)

	if err != nil {
		fmt.Printf("Could not load seelog configuration: %s\n", err)
		return
	}

	log.ReplaceLogger(logger)
}
Пример #11
0
// Initialize logging from command arguments.
func initLogging(configFile string) {
	var err error
	log.RegisterReceiver("stderr", &CustomReceiver{})
	if configFile == "" {
		logger, err = log.LoggerFromConfigAsString(defaultLoggingConfig)
		checkLogFatal("Failed to load default logging configuration: %s", err)
	} else {
		logger, err = log.LoggerFromConfigAsFile(configFile)
		checkLogFatal("Failed to initialize custom logging file %s: %s", configFile, err)
	}
}
Пример #12
0
func main() {
	logger, err := log.LoggerFromConfigAsString("<seelog type=\"asynctimer\" asyncinterval=\"500000000\"/>")
	checkFail(err)
	log.ReplaceLogger(logger)
	defer log.Flush()
	println("start")

	log.Info("Hello from Seelog!")

	time.Sleep(time.Second * 10)
}
Пример #13
0
// Init logger factory.
func initLoggerFactory() error {
	c.LoggerFactory = map[string]Log.LoggerInterface{}
	for loggerName, config := range c.Config.Logger { // convert logger config to inst
		if logInstance, err := Log.LoggerFromConfigAsString(config); err == nil {
			c.LoggerFactory[loggerName] = logInstance
		} else {
			return err
		}
	}

	return nil
}
Пример #14
0
func main() {
	defer seelog.Flush()

	seelog.LoggerFromConfigAsString("formatid=\"debug\"")

	flag.Parse()

	cfg := FtpCfg{*host, *user, *pw, *port}
	fClient, err := NewFtpClient(cfg)
	if err != nil {
		panic(err)
	}
	iClient, err := NewInfluxClient(*surl, *db)
	if err != nil {
		panic(err)
	}

	files := make([]*FtpToInflux, 0)

	scanner := bufio.NewScanner(os.Stdin)
	for scanner.Scan() {
		line := scanner.Text()
		seelog.Tracef("Handle line '%s'", line)
		if strings.HasPrefix(line, commentPrefix) {
			//Comment
			continue
		}
		splittedLine := strings.Split(line, space)
		if len(splittedLine) != 2 {
			seelog.Warnf("Line '%s' has not exactly one space", line)
			continue
		}
		data := &FtpToInflux{splittedLine[0], strings.Split(splittedLine[1], sep)}
		files = append(files, data)
	}

	for _, f := range files {
		seelog.Tracef("Start with file '%s'!", f.Filename)
		buf, err := fClient.Download(f.Filename)
		if err != nil {
			seelog.Warnf("Error downloading file '%s': %v", f.Filename, err)
			continue
		}
		datas := Transform(buf)
		err = iClient.Write(datas, f.Measurements)
		if err != nil {
			seelog.Warnf("Error writing Data: %v", err)
			continue
		}
		seelog.Tracef("File '%s' downloaded and written to %d measurements!", f.Filename, len(f.Measurements))
	}
}
Пример #15
0
func main() {
	cluster := gocql.NewCluster("127.0.0.1")
	cluster.Keyspace = "system"
	session, err := cluster.CreateSession()
	defer session.Close()

	if err != nil {
		log.Critical(err)
	}

	traceSession, err := cluster.CreateSession()
	defer session.Close()

	if err != nil {
		log.Critical(err)
	}

	// Create a new logger instance that we adjust the stack depth for to get
	// more meaningful frames
	logger, err := log.LoggerFromConfigAsString(
		`<seelog>
            <outputs>
                <console formatid="fmt"/>
            </outputs>
            <formats>
                <format id="fmt" format="%Date(Jan 02 2006 03:04:05.000) [%LEVEL] %File:%Line - %Msg%n"/>
            </formats>
        </seelog>
        `)
	logger.SetAdditionalStackDepth(2)

	if err != nil {
		log.Critical(err)
	}

	writer := NewTraceWriter(traceSession, logger)
	tracer := gocql.NewTraceWriter(traceSession, writer)
	session.SetTrace(tracer)

	var count int
	iter := session.Query(`select count(*) from schema_keyspaces`).Iter()
	iter.Scan(&count)

	err = iter.Close()

	if err != nil {
		log.Critical(err)
	}

	log.Infof("This instance has %d keyspaces", count)
}
Пример #16
0
func init() {
	_, console = config.GetStringMapBool("log", "console")
	_, appendfile = config.GetStringMapBool("log", "appendfile")
	_, file = config.GetStringMapString("log", "file")
	if file == "" {
		file = "./log/omega-es.log"
	}
	logger, err := log.LoggerFromConfigAsString(logConfig())
	if err == nil {
		log.ReplaceLogger(logger)
	} else {
		log.Error(err)
	}
}
Пример #17
0
Файл: rmq.go Проект: relops/rmq
func init() {
	opts.AdvertizedVersion = VERSION
	opts.Version = printVersionAndExit

	// We might want to make this overridable
	logger, err := log.LoggerFromConfigAsString(logConfig)

	if err != nil {
		fmt.Printf("Could not load seelog configuration: %s\n", err)
		return
	}

	log.ReplaceLogger(logger)
}
Пример #18
0
func initForTest() {
	config := `
<seelog type="sync" minlevel="trace">
    <outputs formatid="common">
        <console />
    </outputs>
    <formats>
        <format id="common" format="2015-04-01 12:34:56.789 [%LEV] %Msg%n"/>
    </formats>
</seelog>`
	logger, _ := seelog.LoggerFromConfigAsString(config)
	mutex = new(sync.Mutex)
	seelog.ReplaceLogger(logger)
	isValid = true
}
Пример #19
0
func initForTest() {
	config := `
<seelog type="sync" minlevel="trace">
    <outputs formatid="common">
        <console />
    </outputs>
    <formats>
        <format id="common" format="2015-04-01 12:34:56.789 [%LEV] %Msg%n"/>
    </formats>
</seelog>`
	logger, _ := seelog.LoggerFromConfigAsString(config)
	locker, _ = util.InitLock(lockName)
	seelog.ReplaceLogger(logger)
	valid = true
}
Пример #20
0
// InstallTestLogger will install a logger with appropriate configuration for the current testing setup. It returns a
// the logger that was overwritten; this should be restored (via a call to RestoreLogger) at the conclusion of the test.
func InstallTestLoggerWithLogLevel(t testing.TB, logLevel string) log.LoggerInterface {
	golog.SetOutput(ioutil.Discard)

	loggerIdNum++
	loggerId := fmt.Sprintf("testLogger%d", loggerIdNum)

	log.RegisterReceiver(loggerId, &testLogger{tb: t})

	config := fmt.Sprintf(testLoggerConfigTemplate, logLevel, loggerId)
	if logger, err := log.LoggerFromConfigAsString(config); err != nil {
		panic(err)
	} else {
		stashed := log.Current
		log.ReplaceLogger(logger)
		return stashed
	}
}
Пример #21
0
// Init initializes logger.
func Init() error {
	logfile := filepath.Join(config.Log.OutputDir, logFileName)
	if err := makeFileIfNotExist(logfile); err != nil {
		return err
	}

	logconf := generateConfigString(logfile)
	logger, err := seelog.LoggerFromConfigAsString(logconf)
	if err != nil {
		return err
	}

	seelog.ReplaceLogger(logger)
	mutex = new(sync.Mutex)
	isValid = true

	return nil
}
Пример #22
0
// Init initializes the Mute logging framework to the given logging level.
// If logDir is not nil logging is done to a logfile in the directory.
// If logToConsole is true the console logging is activated.
// cmdPrefix must be a 5 character long command prefix.
// If the given level is invalid or the initialization fails, an
// error is returned.
func Init(logLevel, cmdPrefix, logDir string, logToConsole bool) error {
	// check level string
	_, found := seelog.LogLevelFromString(logLevel)
	if !found {
		return fmt.Errorf("log: level '%s' is invalid", logLevel)
	}
	// check cmdPrefix
	if len(cmdPrefix) != 5 {
		return fmt.Errorf("len(cmdPrefix) must be 5: %q", cmdPrefix)
	}
	// create logger
	console := "<console />"
	if !logToConsole {
		console = ""
	}
	var file string
	if logDir != "" {
		execBase := strings.TrimSuffix(filepath.Base(os.Args[0]), ".exe")
		file = fmt.Sprintf("<rollingfile type=\"size\" filename=%q maxsize=\"10485760\" maxrolls=\"3\" />",
			filepath.Join(logDir, execBase+".log"))
	}
	config := `
<seelog type="adaptive" mininterval="2000000" maxinterval="100000000"
	critmsgcount="500" minlevel="%s">
	<outputs formatid="all">
		%s
		%s
	</outputs>
	<formats>
		<format id="all" format="%%UTCDate %%UTCTime [%s] [%%LEV] %%Msg%%n" />
	</formats>
</seelog>`
	config = fmt.Sprintf(config, logLevel, console, file, cmdPrefix)
	logger, err := seelog.LoggerFromConfigAsString(config)
	if err != nil {
		return err
	}
	logger.SetAdditionalStackDepth(1)
	// replace logger
	UseLogger(logger)
	// log info about running binary
	Infof("%s started (built with %s %s for %s/%s)", os.Args[0], runtime.Compiler, runtime.Version(), runtime.GOOS, runtime.GOARCH)
	return nil
}
Пример #23
0
// loads logger from config file
func UseLoggerFromConfigFile(filename string) {
	if filename == "" {
		filename = "seelog.xml"
	}
	newLogger, err := seelog.LoggerFromConfigAsFile(filename)
	if err != nil {
		log.Printf("cannot read %s: %s", filename, err)
		if LogIsDisabled() {
			newLogger, e := seelog.LoggerFromConfigAsString(DefaultLogConf)
			if e != nil {
				log.Printf("cannot load logger config: %s", e)
			}
			UseLogger(newLogger)
		}
		logger.Error("cannot read %s: %s", filename, err)
	} else {
		UseLogger(newLogger)
	}
}
Пример #24
0
func init() {
	var ConfigFile string
	flag.StringVar(&ConfigFile, "config", "config.cfg.example",
		"Please provide the path to the config file, defaults to: /etc/gosync/config.cfg")
	flag.Parse()
	if _, err := os.Stat(ConfigFile); os.IsNotExist(err) {
		log.Criticalf("Configuration file does not exist or cannot be loaded: (%s)", ConfigFile)
		os.Exit(1)
	} else {
		utils.ReadConfigFromFile(ConfigFile)
	}

	logger, err := log.LoggerFromConfigAsString(getLoggerConfig())

	if err == nil {
		log.ReplaceLogger(logger)
	}

}
Пример #25
0
func signalCatcher() {
	var logLock sync.Mutex // Ensure we only process one log switch at once
	enableTrace := func(sig os.Signal) {
		logLock.Lock()
		defer logLock.Unlock()

		previousLogger := log.Current
		newLogger, err := log.LoggerFromConfigAsString(traceLoggingLevel)
		if err != nil {
			log.Warnf("[Service] Unable to construct trace logger: %s", err.Error())
			return
		}
		log.ReplaceLogger(newLogger)
		log.Tracef("[Service] Enabled trace logging for %s (in response to %s)", traceLoggingTimeout.String(),
			sig.String())
		time.Sleep(traceLoggingTimeout)
		log.Tracef("[Service] Reverting to previous logger")
		log.ReplaceLogger(previousLogger)
	}

	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGUSR1)
	defer signal.Stop(c)

	for sig := range c {
		if sig == syscall.SIGUSR1 {
			go enableTrace(sig)
		} else {
			log.Infof("[Service] Received signal: %s", sig.String())
			cleanup()
			if sig == syscall.SIGQUIT { // Print stack dump
				buf := make([]byte, 1<<16)
				os.Stderr.Write([]byte("SIGQUIT: core dump\n\n"))
				os.Stderr.Write(buf[:runtime.Stack(buf, true)])
			}
			break
		}
	}

	os.Exit(2)
}
Пример #26
0
//InitLogger
func InitLogger(props utils.Properties) {
	logType := props.GetStringWithDefault("log.type", "sync")
	typeStr := ""
	if logType == "sync" {
		typeStr = `type="sync"`
	} else if logType == "asynctimer" {
		asyncInterval := props.GetIntWithDefault("log.asyncinterval", 5000000)
		typeStr = `type="asynctimer" asyncinterval="` + strconv.Itoa(asyncInterval) + `"`
	}
	minLevel := props.GetStringWithDefault("log.minlevel", "info")
	maxlevel := props.GetStringWithDefault("log.maxlevel", "error")
	logDir := props.GetStringWithDefault("log.dirs", "./log")
	segmentBytes := props.GetIntWithDefault("log.segment.bytes", 53687092)
	segmentRolls := props.GetIntWithDefault("log.segment.rolls", 5)

	logConfig := `
		<seelog ` + typeStr + ` minlevel="` + minLevel + `" maxlevel="` + maxlevel + `">
				<outputs formatid="main">
				    <console/>
						<rollingfile type="size" filename="` + logDir + `/server.log" maxsize="` + strconv.Itoa(segmentBytes) + `" maxrolls="` + strconv.Itoa(segmentRolls) + `"/>
					  <filter levels="error">
								<file path="` + logDir + `/error.log"/>
						</filter>
				</outputs>
				<formats>
						<format id="main" format="%Date(2006 Jan 02 3:04:05.000000000 PM MST) [%Level] %Msg%n"/>
				</formats>
		</seelog>
	`
	mylogger, err := log.LoggerFromConfigAsString(logConfig)
	//fmt.Println(logConfig)
	//mylogger, err := log.LoggerFromConfigAsFile("../config/log.xml")
	if err != nil {
		fmt.Println("load seelog config fail:", err)
	}
	log.ReplaceLogger(mylogger)
}
Пример #27
0
func newLuaState(conf string) *lua.LState {
	L := lua.NewState()

	registerIRCChatClientType(L)
	registerSlackChatClientType(L)
	registerHipchatChatClientType(L)
	registerNullChatClientType(L)
	mod := L.SetFuncs(L.NewTable(), map[string]lua.LGFunction{
		"newbot": func(L *lua.LState) int {
			opt := L.OptTable(2, L.NewTable())
			co := newCommonClientOption(conf)
			switch v := L.GetField(opt, "log").(type) {
			case *lua.LFunction:
				co.Logger = log.New(&luaLogger{L, v}, "", log.LstdFlags)
			case *lua.LTable:
				l, err := seelog.LoggerFromConfigAsString(luaToXml(v))
				if err != nil {
					L.RaiseError(err.Error())
				}
				co.Logger = log.New(&seelogLogger{l}, "", 0)
			}
			if s, ok := getStringField(L, opt, "http"); ok {
				co.HttpAddr = s
			}
			if tbl, ok := L.GetField(opt, "https").(*lua.LTable); ok {
				if s, ok := getStringField(L, tbl, "addr"); ok {
					co.Https.Addr = s
				}
				if s, ok := getStringField(L, tbl, "cert"); ok {
					co.Https.CertFile = s
				}
				if s, ok := getStringField(L, tbl, "key"); ok {
					co.Https.KeyFile = s
				}
			}
			if tbl, ok := L.GetField(opt, "crons").(*lua.LTable); ok {
				co.Crons = []CronEntry{}
				tbl.ForEach(func(key, value lua.LValue) {
					entry := value.(*lua.LTable)
					co.Crons = append(co.Crons, CronEntry{entry.RawGetInt(1).String(), entry.RawGetInt(2).String()})
				})
			}

			switch L.CheckString(1) {
			case "IRC":
				newIRCChatClient(L, co, opt)
			case "Slack":
				newSlackChatClient(L, co, opt)
			case "Hipchat":
				newHipchatChatClient(L, co, opt)
			case "Null":
				newNullChatClient(L, co, opt)
			default:
				L.RaiseError("unknown chat type: %s", L.ToString(1))
			}
			return 1
		},
		"newlogger": func(L *lua.LState) int {
			logger, err := seelog.LoggerFromConfigAsString(luaToXml(L.CheckTable(1)))
			if err != nil {
				L.RaiseError(err.Error())
			}
			L.Push(luar.New(L, log.New(&seelogLogger{logger}, "", 0)))
			return 1
		},
	})
	L.SetField(mod, "cmain", lua.LChannel(luaMainChan))
	L.SetField(mod, "cworker", lua.LChannel(luaWorkerChan))
	proxyLuar(L, MessageEvent{}, nil)
	proxyLuar(L, log.Logger{}, nil)
	proxyLuar(L, url.Values{}, nil)
	proxyLuar(L, url.Userinfo{}, nil)
	proxyLuar(L, url.URL{}, nil)
	proxyLuar(L, http.Cookie{}, nil)
	proxyLuar(L, http.Header{}, nil)
	proxyLuar(L, http.Request{}, func(L *lua.LState, key string) bool {
		if key == "readbody" || key == "ReadBody" {
			L.Push(L.NewFunction(func(L *lua.LState) int {
				r := L.CheckUserData(1).Value.(*http.Request)
				b, err := ioutil.ReadAll(r.Body)
				defer r.Body.Close()
				if err != nil {
					pushN(L, lua.LNil, lua.LString(err.Error()))
					return 2
				}
				pushN(L, lua.LString(b))
				return 1
			}))
			return true
		}
		return false
	})

	L.PreloadModule("golbot", func(L *lua.LState) int {
		L.Push(mod)
		return 1
	})
	L.PreloadModule("charset", func(L *lua.LState) int {
		L.Push(L.SetFuncs(L.NewTable(), charsetMod))
		return 1
	})
	L.PreloadModule("requests", func(L *lua.LState) int {
		L.Push(L.SetFuncs(L.NewTable(), requestsMod))
		return 1
	})
	luajson.Preload(L)
	L.PreloadModule("re", gluare.Loader)
	L.PreloadModule("sh", gluash.Loader)
	L.PreloadModule("fs", gluafs.Loader)
	L.SetGlobal("goworker", L.NewFunction(func(L *lua.LState) int {
		go func() {
			L := newLuaState(conf)
			pushN(L, L.GetGlobal("worker"), <-luaWorkerChan)
			L.PCall(1, 0, nil)
		}()
		luaWorkerChan <- L.CheckAny(1)
		return 0
	}))

	if err := L.DoString(`
      local golbot = require("golbot")
      local requests = require("requests")
      local json = require("json")
      notifymain  = function(msg) golbot.cmain:send(msg) end
      requestmain = function(msg)
        msg._result = channel.make()
        golbot.cmain:send(msg)
        return msg._result:receive()
      end
      respond = function(msg, value)
        if msg and msg._result then
          msg._result:send(value)
        end
      end
      requests.json = function(opt)
	    local headers = opt.headers or {}
		opt.headers = headers
		local found = false
		for i, v in ipairs(headers) do
		    if i%2 == 0 and string.lower(v) == "content-type" then
			  found = true
			  break
			end
		end
		if not found then
		  table.insert(headers, "Content-Type")
		  table.insert(headers, "application/json")
		end
        jdata, e = json.encode(opt.json)
		if jdata == nil then
		  return jdata, e
		end
		opt.data = jdata
		body, resp = requests.request(opt)
		if body == nil then
		  return body, resp
		end
		return json.decode(body), resp
      end
	`); err != nil {
		panic(err)
	}
	if err := L.DoFile(conf); err != nil {
		panic(err)
	}
	return L
}