func SetConfig(source interface{}, others ...interface{}) (_ *ini.File, err error) {
	cfg, err = ini.Load(source, others...)
	return Config(), err
}

func SetConfig ( source interface { } , others ... interface { } ) ( _ * ini . File , err error ) { cfg , err = ini . Load ( source , others ... ) return Config ( ) , err }

// SetConfig sets data sources for configuration.

SetConfig sets data sources for configuration .


func (rb *RequestBody) String() (string, error) {
	data, err := rb.Bytes()
	return string(data), err
}

func ( rb * RequestBody ) String ( ) ( string , error ) { data , err := rb . Bytes ( ) return string ( data ) , err }

// String reads and returns content of request body in string.

String reads and returns content of request body in string .


func (ctx *Context) RemoteAddr() string {
	addr := ctx.Req.Header.Get("X-Real-IP")
	if len(addr) == 0 {
		addr = ctx.Req.Header.Get("X-Forwarded-For")
		if addr == "" {
			addr = ctx.Req.RemoteAddr
			if i := strings.LastIndex(addr, ":"); i > -1 {
				addr = addr[:i]
			}
		}
	}
	return addr
}

func ( ctx * Context ) RemoteAddr ( ) string { addr := ctx . Req . Header . Get ( " " ) if len ( addr ) == 0 { addr = ctx . Req . Header . Get ( " " ) if addr == " " { addr = ctx . Req . RemoteAddr if i := strings . LastIndex ( addr , " " ) ; i > - 1 { addr = addr [ : i ] } } } return addr }

// RemoteAddr returns more real IP address.

RemoteAddr returns more real IP address .


func (ctx *Context) HTML(status int, name string, data ...interface{}) {
	ctx.renderHTML(status, DEFAULT_TPL_SET_NAME, name, data...)
}

func ( ctx * Context ) HTML ( status int , name string , data ... interface { } ) { ctx . renderHTML ( status , DEFAULT_TPL_SET_NAME , name , data ... ) }

// HTML renders the HTML with default template set.

HTML renders the HTML with default template set .


func (ctx *Context) HTMLSet(status int, setName, tplName string, data ...interface{}) {
	ctx.renderHTML(status, setName, tplName, data...)
}

func ( ctx * Context ) HTMLSet ( status int , setName , tplName string , data ... interface { } ) { ctx . renderHTML ( status , setName , tplName , data ... ) }

// HTMLSet renders the HTML with given template set name.

HTMLSet renders the HTML with given template set name .


func (ctx *Context) Query(name string) string {
	ctx.parseForm()
	return ctx.Req.Form.Get(name)
}

func ( ctx * Context ) Query ( name string ) string { ctx . parseForm ( ) return ctx . Req . Form . Get ( name ) }


func (ctx *Context) QueryTrim(name string) string {
	return strings.TrimSpace(ctx.Query(name))
}

func ( ctx * Context ) QueryTrim ( name string ) string { return strings . TrimSpace ( ctx . Query ( name ) ) }

// QueryTrim querys and trims spaces form parameter.

QueryTrim querys and trims spaces form parameter .


func (ctx *Context) QueryStrings(name string) []string {
	ctx.parseForm()

	vals, ok := ctx.Req.Form[name]
	if !ok {
		return []string{}
	}
	return vals
}

func ( ctx * Context ) QueryStrings ( name string ) [ ] string { ctx . parseForm ( ) vals , ok := ctx . Req . Form [ name ] if ! ok { return [ ] string { } } return vals }

// QueryStrings returns a list of results by given query name.

QueryStrings returns a list of results by given query name .


func (ctx *Context) QueryEscape(name string) string {
	return template.HTMLEscapeString(ctx.Query(name))
}

func ( ctx * Context ) QueryEscape ( name string ) string { return template . HTMLEscapeString ( ctx . Query ( name ) ) }

// QueryEscape returns escapred query result.

QueryEscape returns escapred query result .


func (ctx *Context) QueryBool(name string) bool {
	v, _ := strconv.ParseBool(ctx.Query(name))
	return v
}

func ( ctx * Context ) QueryBool ( name string ) bool { v , _ := strconv . ParseBool ( ctx . Query ( name ) ) return v }

// QueryBool returns query result in bool type.

QueryBool returns query result in bool type .


func (ctx *Context) QueryInt(name string) int {
	return com.StrTo(ctx.Query(name)).MustInt()
}

func ( ctx * Context ) QueryInt ( name string ) int { return com . StrTo ( ctx . Query ( name ) ) . MustInt ( ) }

// QueryInt returns query result in int type.

QueryInt returns query result in int type .


func (ctx *Context) QueryInt64(name string) int64 {
	return com.StrTo(ctx.Query(name)).MustInt64()
}

func ( ctx * Context ) QueryInt64 ( name string ) int64 { return com . StrTo ( ctx . Query ( name ) ) . MustInt64 ( ) }

// QueryInt64 returns query result in int64 type.

QueryInt64 returns query result in int64 type .


func (ctx *Context) QueryFloat64(name string) float64 {
	v, _ := strconv.ParseFloat(ctx.Query(name), 64)
	return v
}

func ( ctx * Context ) QueryFloat64 ( name string ) float64 { v , _ := strconv . ParseFloat ( ctx . Query ( name ) , 64 ) return v }

// QueryFloat64 returns query result in float64 type.

QueryFloat64 returns query result in float64 type .


func (ctx *Context) SetParams(name, val string) {
	if name != "*" && !strings.HasPrefix(name, ":") {
		name = ":" + name
	}
	ctx.params[name] = val
}

func ( ctx * Context ) SetParams ( name , val string ) { if name != " " && ! strings . HasPrefix ( name , " " ) { name = " " + name } ctx . params [ name ] = val }

// SetParams sets value of param with given name.

SetParams sets value of param with given name .


func (ctx *Context) GetFile(name string) (multipart.File, *multipart.FileHeader, error) {
	return ctx.Req.FormFile(name)
}

func ( ctx * Context ) GetFile ( name string ) ( multipart . File , * multipart . FileHeader , error ) { return ctx . Req . FormFile ( name ) }

// GetFile returns information about user upload file by given form field name.

GetFile returns information about user upload file by given form field name .


func (ctx *Context) SaveToFile(name, savePath string) error {
	fr, _, err := ctx.GetFile(name)
	if err != nil {
		return err
	}
	defer fr.Close()

	fw, err := os.OpenFile(savePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
	if err != nil {
		return err
	}
	defer fw.Close()

	_, err = io.Copy(fw, fr)
	return err
}

func ( ctx * Context ) SaveToFile ( name , savePath string ) error { fr , _ , err := ctx . GetFile ( name ) if err != nil { return err } defer fr . Close ( ) fw , err := os . OpenFile ( savePath , os . O_WRONLY | os . O_CREATE | os . O_TRUNC , 0666 ) if err != nil { return err } defer fw . Close ( ) _ , err = io . Copy ( fw , fr ) return err }

// SaveToFile reads a file from request by field name and saves to given path.

SaveToFile reads a file from request by field name and saves to given path .


func (ctx *Context) GetCookie(name string) string {
	cookie, err := ctx.Req.Cookie(name)
	if err != nil {
		return ""
	}
	val, _ := url.QueryUnescape(cookie.Value)
	return val
}

func ( ctx * Context ) GetCookie ( name string ) string { cookie , err := ctx . Req . Cookie ( name ) if err != nil { return " " } val , _ := url . QueryUnescape ( cookie . Value ) return val }

// GetCookie returns given cookie value from request header.

GetCookie returns given cookie value from request header .


func (ctx *Context) GetCookieInt(name string) int {
	return com.StrTo(ctx.GetCookie(name)).MustInt()
}

func ( ctx * Context ) GetCookieInt ( name string ) int { return com . StrTo ( ctx . GetCookie ( name ) ) . MustInt ( ) }

// GetCookieInt returns cookie result in int type.

GetCookieInt returns cookie result in int type .


func (ctx *Context) GetCookieInt64(name string) int64 {
	return com.StrTo(ctx.GetCookie(name)).MustInt64()
}

func ( ctx * Context ) GetCookieInt64 ( name string ) int64 { return com . StrTo ( ctx . GetCookie ( name ) ) . MustInt64 ( ) }

// GetCookieInt64 returns cookie result in int64 type.

GetCookieInt64 returns cookie result in int64 type .


func (ctx *Context) GetCookieFloat64(name string) float64 {
	v, _ := strconv.ParseFloat(ctx.GetCookie(name), 64)
	return v
}

func ( ctx * Context ) GetCookieFloat64 ( name string ) float64 { v , _ := strconv . ParseFloat ( ctx . GetCookie ( name ) , 64 ) return v }

// GetCookieFloat64 returns cookie result in float64 type.

GetCookieFloat64 returns cookie result in float64 type .


func (ctx *Context) SetSecureCookie(name, value string, others ...interface{}) {
	ctx.SetSuperSecureCookie(defaultCookieSecret, name, value, others...)
}

func ( ctx * Context ) SetSecureCookie ( name , value string , others ... interface { } ) { ctx . SetSuperSecureCookie ( defaultCookieSecret , name , value , others ... ) }

// SetSecureCookie sets given cookie value to response header with default secret string.

SetSecureCookie sets given cookie value to response header with default secret string .


func (ctx *Context) GetSecureCookie(key string) (string, bool) {
	return ctx.GetSuperSecureCookie(defaultCookieSecret, key)
}

func ( ctx * Context ) GetSecureCookie ( key string ) ( string , bool ) { return ctx . GetSuperSecureCookie ( defaultCookieSecret , key ) }

// GetSecureCookie returns given cookie value from request header with default secret string.

GetSecureCookie returns given cookie value from request header with default secret string .


func (ctx *Context) SetSuperSecureCookie(secret, name, value string, others ...interface{}) {
	key := pbkdf2.Key([]byte(secret), []byte(secret), 1000, 16, sha256.New)
	text, err := com.AESGCMEncrypt(key, []byte(value))
	if err != nil {
		panic("error encrypting cookie: " + err.Error())
	}

	ctx.SetCookie(name, hex.EncodeToString(text), others...)
}

func ( ctx * Context ) SetSuperSecureCookie ( secret , name , value string , others ... interface { } ) { key := pbkdf2 . Key ( [ ] byte ( secret ) , [ ] byte ( secret ) , 1000 , 16 , sha256 . New ) text , err := com . AESGCMEncrypt ( key , [ ] byte ( value ) ) if err != nil { panic ( " " + err . Error ( ) ) } ctx . SetCookie ( name , hex . EncodeToString ( text ) , others ... ) }

// SetSuperSecureCookie sets given cookie value to response header with secret string.

SetSuperSecureCookie sets given cookie value to response header with secret string .


func (ctx *Context) GetSuperSecureCookie(secret, name string) (string, bool) {
	val := ctx.GetCookie(name)
	if val == "" {
		return "", false
	}

	text, err := hex.DecodeString(val)
	if err != nil {
		return "", false
	}

	key := pbkdf2.Key([]byte(secret), []byte(secret), 1000, 16, sha256.New)
	text, err = com.AESGCMDecrypt(key, text)
	return string(text), err == nil
}

func ( ctx * Context ) GetSuperSecureCookie ( secret , name string ) ( string , bool ) { val := ctx . GetCookie ( name ) if val == " " { return " " , false } text , err := hex . DecodeString ( val ) if err != nil { return " " , false } key := pbkdf2 . Key ( [ ] byte ( secret ) , [ ] byte ( secret ) , 1000 , 16 , sha256 . New ) text , err = com . AESGCMDecrypt ( key , text ) return string ( text ) , err == nil }

// GetSuperSecureCookie returns given cookie value from request header with secret string.

GetSuperSecureCookie returns given cookie value from request header with secret string .


func (ctx *Context) ServeContent(name string, r io.ReadSeeker, params ...interface{}) {
	modtime := time.Now()
	for _, p := range params {
		switch v := p.(type) {
		case time.Time:
			modtime = v
		}
	}

	ctx.setRawContentHeader()
	http.ServeContent(ctx.Resp, ctx.Req.Request, name, modtime, r)
}

func ( ctx * Context ) ServeContent ( name string , r io . ReadSeeker , params ... interface { } ) { modtime := time . Now ( ) for _ , p := range params { switch v := p . ( type ) { case time . Time : modtime = v } } ctx . setRawContentHeader ( ) http . ServeContent ( ctx . Resp , ctx . Req . Request , name , modtime , r ) }

// ServeContent serves given content to response.

ServeContent serves given content to response .


func (ctx *Context) ServeFileContent(file string, names ...string) {
	var name string
	if len(names) > 0 {
		name = names[0]
	} else {
		name = path.Base(file)
	}

	f, err := os.Open(file)
	if err != nil {
		if Env == PROD {
			http.Error(ctx.Resp, "Internal Server Error", 500)
		} else {
			http.Error(ctx.Resp, err.Error(), 500)
		}
		return
	}
	defer f.Close()

	ctx.setRawContentHeader()
	http.ServeContent(ctx.Resp, ctx.Req.Request, name, time.Now(), f)
}

func ( ctx * Context ) ServeFileContent ( file string , names ... string ) { var name string if len ( names ) > 0 { name = names [ 0 ] } else { name = path . Base ( file ) } f , err := os . Open ( file ) if err != nil { if Env == PROD { http . Error ( ctx . Resp , " " , 500 ) } else { http . Error ( ctx . Resp , err . Error ( ) , 500 ) } return } defer f . Close ( ) ctx . setRawContentHeader ( ) http . ServeContent ( ctx . Resp , ctx . Req . Request , name , time . Now ( ) , f ) }

// ServeFileContent serves given file as content to response.

ServeFileContent serves given file as content to response .


func (ctx *Context) ServeFile(file string, names ...string) {
	var name string
	if len(names) > 0 {
		name = names[0]
	} else {
		name = path.Base(file)
	}
	ctx.Resp.Header().Set("Content-Description", "File Transfer")
	ctx.Resp.Header().Set("Content-Type", "application/octet-stream")
	ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+name)
	ctx.Resp.Header().Set("Content-Transfer-Encoding", "binary")
	ctx.Resp.Header().Set("Expires", "0")
	ctx.Resp.Header().Set("Cache-Control", "must-revalidate")
	ctx.Resp.Header().Set("Pragma", "public")
	http.ServeFile(ctx.Resp, ctx.Req.Request, file)
}

func ( ctx * Context ) ServeFile ( file string , names ... string ) { var name string if len ( names ) > 0 { name = names [ 0 ] } else { name = path . Base ( file ) } ctx . Resp . Header ( ) . Set ( " " , " " ) ctx . Resp . Header ( ) . Set ( " " , " " ) ctx . Resp . Header ( ) . Set ( " " , " " + name ) ctx . Resp . Header ( ) . Set ( " " , " " ) ctx . Resp . Header ( ) . Set ( " " , " " ) ctx . Resp . Header ( ) . Set ( " " , " " ) ctx . Resp . Header ( ) . Set ( " " , " " ) http . ServeFile ( ctx . Resp , ctx . Req . Request , file ) }

// ServeFile serves given file to response.

ServeFile serves given file to response .


func (ctx *Context) ChangeStaticPath(oldPath, newPath string) {
	if !filepath.IsAbs(oldPath) {
		oldPath = filepath.Join(Root, oldPath)
	}
	dir := statics.Get(oldPath)
	if dir != nil {
		statics.Delete(oldPath)

		if !filepath.IsAbs(newPath) {
			newPath = filepath.Join(Root, newPath)
		}
		*dir = http.Dir(newPath)
		statics.Set(dir)
	}
}

func ( ctx * Context ) ChangeStaticPath ( oldPath , newPath string ) { if ! filepath . IsAbs ( oldPath ) { oldPath = filepath . Join ( Root , oldPath ) } dir := statics . Get ( oldPath ) if dir != nil { statics . Delete ( oldPath ) if ! filepath . IsAbs ( newPath ) { newPath = filepath . Join ( Root , newPath ) } * dir = http . Dir ( newPath ) statics . Set ( dir ) } }

// ChangeStaticPath changes static path from old to new one.

ChangeStaticPath changes static path from old to new one .


func getNextWildcard(pattern string) (wildcard, _ string) {
	pos := wildcardPattern.FindStringIndex(pattern)
	if pos == nil {
		return "", pattern
	}
	wildcard = pattern[pos[0]:pos[1]]

	// Reach last character or no regexp is given.
	if len(pattern) == pos[1] {
		return wildcard, strings.Replace(pattern, wildcard, `(.+)`, 1)
	} else if pattern[pos[1]] != '(' {
		switch {
		case isSpecialRegexp(pattern, ":int", pos):
			pattern = strings.Replace(pattern, ":int", "([0-9]+)", 1)
		case isSpecialRegexp(pattern, ":string", pos):
			pattern = strings.Replace(pattern, ":string", "([\\w]+)", 1)
		default:
			return wildcard, strings.Replace(pattern, wildcard, `(.+)`, 1)
		}
	}

	// Cut out placeholder directly.
	return wildcard, pattern[:pos[0]] + pattern[pos[1]:]
}

// getNextWildcard tries to find next wildcard and update pattern with corresponding regexp.

getNextWildcard tries to find next wildcard and update pattern with corresponding regexp .


func getRawPattern(rawPattern string) string {
	rawPattern = strings.Replace(rawPattern, ":int", "", -1)
	rawPattern = strings.Replace(rawPattern, ":string", "", -1)

	for {
		startIdx := strings.Index(rawPattern, "(")
		if startIdx == -1 {
			break
		}

		closeIdx := strings.Index(rawPattern, ")")
		if closeIdx > -1 {
			rawPattern = rawPattern[:startIdx] + rawPattern[closeIdx+1:]
		}
	}
	return rawPattern
}

func getRawPattern ( rawPattern string ) string { rawPattern = strings . Replace ( rawPattern , " " , " " , - 1 ) rawPattern = strings . Replace ( rawPattern , " " , " " , - 1 ) for { startIdx := strings . Index ( rawPattern , " " ) if startIdx == - 1 { break } closeIdx := strings . Index ( rawPattern , " " ) if closeIdx > - 1 { rawPattern = rawPattern [ : startIdx ] + rawPattern [ closeIdx + 1 : ] } } return rawPattern }

// getRawPattern removes all regexp but keeps wildcards for building URL path.

getRawPattern removes all regexp but keeps wildcards for building URL path .


func (l *Leaf) URLPath(pairs ...string) string {
	if len(pairs)%2 != 0 {
		panic("number of pairs does not match")
	}

	urlPath := l.rawPattern
	parent := l.parent
	for parent != nil {
		urlPath = parent.rawPattern + "/" + urlPath
		parent = parent.parent
	}
	for i := 0; i < len(pairs); i += 2 {
		if len(pairs[i]) == 0 {
			panic("pair value cannot be empty: " + com.ToStr(i))
		} else if pairs[i][0] != ':' && pairs[i] != "*" && pairs[i] != "*.*" {
			pairs[i] = ":" + pairs[i]
		}
		urlPath = strings.Replace(urlPath, pairs[i], pairs[i+1], 1)
	}
	return urlPath
}

func ( l * Leaf ) URLPath ( pairs ... string ) string { if len ( pairs ) % 2 != 0 { panic ( " " ) } urlPath := l . rawPattern parent := l . parent for parent != nil { urlPath = parent . rawPattern + " " + urlPath parent = parent . parent } for i := 0 ; i < len ( pairs ) ; i += 2 { if len ( pairs [ i ] ) == 0 { panic ( " " + com . ToStr ( i ) ) } else if pairs [ i ] [ 0 ] != ':' && pairs [ i ] != " " && pairs [ i ] != " " { pairs [ i ] = " " + pairs [ i ] } urlPath = strings . Replace ( urlPath , pairs [ i ] , pairs [ i + 1 ] , 1 ) } return urlPath }

// URLPath build path part of URL by given pair values.

URLPath build path part of URL by given pair values .


func NewRouteMap() *routeMap {
	rm := &routeMap{
		routes: make(map[string]map[string]*Leaf),
	}
	for m := range _HTTP_METHODS {
		rm.routes[m] = make(map[string]*Leaf)
	}
	return rm
}

func NewRouteMap ( ) * routeMap { rm := & routeMap { routes : make ( map [ string ] map [ string ] * Leaf ) , } for m := range _HTTP_METHODS { rm . routes [ m ] = make ( map [ string ] * Leaf ) } return rm }

// NewRouteMap initializes and returns a new routeMap.

NewRouteMap initializes and returns a new routeMap .


func (rm *routeMap) getLeaf(method, pattern string) *Leaf {
	rm.lock.RLock()
	defer rm.lock.RUnlock()

	return rm.routes[method][pattern]
}

func ( rm * routeMap ) getLeaf ( method , pattern string ) * Leaf { rm . lock . RLock ( ) defer rm . lock . RUnlock ( ) return rm . routes [ method ] [ pattern ] }

// getLeaf returns Leaf object if a route has been registered.

getLeaf returns Leaf object if a route has been registered .


func (rm *routeMap) add(method, pattern string, leaf *Leaf) {
	rm.lock.Lock()
	defer rm.lock.Unlock()

	rm.routes[method][pattern] = leaf
}

func ( rm * routeMap ) add ( method , pattern string , leaf * Leaf ) { rm . lock . Lock ( ) defer rm . lock . Unlock ( ) rm . routes [ method ] [ pattern ] = leaf }

// add adds new route to route tree map.


func (r *Route) Name(name string) {
	if len(name) == 0 {
		panic("route name cannot be empty")
	} else if r.router.namedRoutes[name] != nil {
		panic("route with given name already exists: " + name)
	}
	r.router.namedRoutes[name] = r.leaf
}

func ( r * Route ) Name ( name string ) { if len ( name ) == 0 { panic ( " " ) } else if r . router . namedRoutes [ name ] != nil { panic ( " " + name ) } r . router . namedRoutes [ name ] = r . leaf }


func (r *Router) handle(method, pattern string, handle Handle) *Route {
	method = strings.ToUpper(method)

	var leaf *Leaf
	// Prevent duplicate routes.
	if leaf = r.getLeaf(method, pattern); leaf != nil {
		return &Route{r, leaf}
	}

	// Validate HTTP methods.
	if !_HTTP_METHODS[method] && method != "*" {
		panic("unknown HTTP method: " + method)
	}

	// Generate methods need register.
	methods := make(map[string]bool)
	if method == "*" {
		for m := range _HTTP_METHODS {
			methods[m] = true
		}
	} else {
		methods[method] = true
	}

	// Add to router tree.
	for m := range methods {
		if t, ok := r.routers[m]; ok {
			leaf = t.Add(pattern, handle)
		} else {
			t := NewTree()
			leaf = t.Add(pattern, handle)
			r.routers[m] = t
		}
		r.add(m, pattern, leaf)
	}
	return &Route{r, leaf}
}

func
(
r
*
Router
)
handle
(
method
,
pattern
string
,
handle
Handle
)
*
Route
{
method
=
strings
.
ToUpper
(
method
)
var
leaf
*
Leaf
// Prevent duplicate routes.
if
leaf
=
r
.
getLeaf
(
method
,
pattern
)
;
leaf
!=
{
return
&
Route
{
r
,
leaf
}
}
// Validate HTTP methods.
if
!
_HTTP_METHODS
[
method
]
&&
method
!=
"
"
{
panic
(
"
"
+
method
)
}
// Generate methods need register.
methods
:=
make
(
map
[
string
]
bool
)
if
method
==
"
"
{
for
m
:=
range
_HTTP_METHODS
{
methods
[
m
]
=
true
}
}
else
{
methods
[
method
]
=
true
}
// Add to router tree.
for
m
:=
range
methods
{
if
t
,
ok
:=
r
.
routers
[
m
]
;
ok
{
leaf
=
t
.
Add
(
pattern
,
handle
)
}
else
{
t
:=
NewTree
(
)
leaf
=
t
.
Add
(
pattern
,
handle
)
r
.
routers
[
m
]
=
t
}
r
.
add
(
m
,
pattern
,
leaf
)
}
return
&
Route
{
r
,
leaf
}
}

// handle adds new route to the router tree.

handle adds new route to the router tree .


func (r *Router) Handle(method string, pattern string, handlers []Handler) *Route {
	if len(r.groups) > 0 {
		groupPattern := ""
		h := make([]Handler, 0)
		for _, g := range r.groups {
			groupPattern += g.pattern
			h = append(h, g.handlers...)
		}

		pattern = groupPattern + pattern
		h = append(h, handlers...)
		handlers = h
	}
	handlers = validateAndWrapHandlers(handlers, r.handlerWrapper)

	return r.handle(method, pattern, func(resp http.ResponseWriter, req *http.Request, params Params) {
		c := r.m.createContext(resp, req)
		c.params = params
		c.handlers = make([]Handler, 0, len(r.m.handlers)+len(handlers))
		c.handlers = append(c.handlers, r.m.handlers...)
		c.handlers = append(c.handlers, handlers...)
		c.run()
	})
}

func ( r * Router ) Handle ( method string , pattern string , handlers [ ] Handler ) * Route { if len ( r . groups ) > 0 { groupPattern := " " h := make ( [ ] Handler , 0 ) for _ , g := range r . groups { groupPattern += g . pattern h = append ( h , g . handlers ... ) } pattern = groupPattern + pattern h = append ( h , handlers ... ) handlers = h } handlers = validateAndWrapHandlers ( handlers , r . handlerWrapper ) return r . handle ( method , pattern , func ( resp http . ResponseWriter , req * http . Request , params Params ) { c := r . m . createContext ( resp , req ) c . params = params c . handlers = make ( [ ] Handler , 0 , len ( r . m . handlers ) + len ( handlers ) ) c . handlers = append ( c . handlers , r . m . handlers ... ) c . handlers = append ( c . handlers , handlers ... ) c . run ( ) } ) }

// Handle registers a new request handle with the given pattern, method and handlers.

Handle registers a new request handle with the given pattern method and handlers .


func (r *Router) Combo(pattern string, h ...Handler) *ComboRouter {
	return &ComboRouter{r, pattern, h, map[string]bool{}, nil}
}

func ( r * Router ) Combo ( pattern string , h ... Handler ) * ComboRouter { return & ComboRouter { r , pattern , h , map [ string ] bool { } , nil } }


func (r *Router) NotFound(handlers ...Handler) {
	handlers = validateAndWrapHandlers(handlers)
	r.notFound = func(rw http.ResponseWriter, req *http.Request) {
		c := r.m.createContext(rw, req)
		c.handlers = make([]Handler, 0, len(r.m.handlers)+len(handlers))
		c.handlers = append(c.handlers, r.m.handlers...)
		c.handlers = append(c.handlers, handlers...)
		c.run()
	}
}

func ( r * Router ) NotFound ( handlers ... Handler ) { handlers = validateAndWrapHandlers ( handlers ) r . notFound = func ( rw http . ResponseWriter , req * http . Request ) { c := r . m . createContext ( rw , req ) c . handlers = make ( [ ] Handler , 0 , len ( r . m . handlers ) + len ( handlers ) ) c . handlers = append ( c . handlers , r . m . handlers ... ) c . handlers = append ( c . handlers , handlers ... ) c . run ( ) } }

// NotFound configurates http.HandlerFunc which is called when no matching route is
// found. If it is not set, http.NotFound is used.
// Be sure to set 404 response code in your handler.

NotFound configurates http . HandlerFunc which is called when no matching route is found . If it is not set http . NotFound is used . Be sure to set 404 response code in your handler .


func (r *Router) InternalServerError(handlers ...Handler) {
	handlers = validateAndWrapHandlers(handlers)
	r.internalServerError = func(c *Context, err error) {
		c.index = 0
		c.handlers = handlers
		c.Map(err)
		c.run()
	}
}

func ( r * Router ) InternalServerError ( handlers ... Handler ) { handlers = validateAndWrapHandlers ( handlers ) r . internalServerError = func ( c * Context , err error ) { c . index = 0 c . handlers = handlers c . Map ( err ) c . run ( ) } }

// InternalServerError configurates handler which is called when route handler returns
// error. If it is not set, default handler is used.
// Be sure to set 500 response code in your handler.

InternalServerError configurates handler which is called when route handler returns error . If it is not set default handler is used . Be sure to set 500 response code in your handler .


func (r *Router) URLFor(name string, pairs ...string) string {
	leaf, ok := r.namedRoutes[name]
	if !ok {
		panic("route with given name does not exists: " + name)
	}
	return leaf.URLPath(pairs...)
}

func ( r * Router ) URLFor ( name string , pairs ... string ) string { leaf , ok := r . namedRoutes [ name ] if ! ok { panic ( " " + name ) } return leaf . URLPath ( pairs ... ) }

// URLFor builds path part of URL by given pair values.

URLFor builds path part of URL by given pair values .


func (cr *ComboRouter) Name(name string) {
	if cr.lastRoute == nil {
		panic("no corresponding route to be named")
	}
	cr.lastRoute.Name(name)
}

func ( cr * ComboRouter ) Name ( name string ) { if cr . lastRoute == nil { panic ( " " ) } cr . lastRoute . Name ( name ) }


func NewResponseWriter(method string, rw http.ResponseWriter) ResponseWriter {
	return &responseWriter{method, rw, 0, 0, nil}
}

func NewResponseWriter ( method string , rw http . ResponseWriter ) ResponseWriter { return & responseWriter { method , rw , 0 , 0 , nil } }

// NewResponseWriter creates a ResponseWriter that wraps an http.ResponseWriter

NewResponseWriter creates a ResponseWriter that wraps an http . ResponseWriter


func Logger() Handler {
	return func(ctx *Context, log *log.Logger) {
		start := time.Now()

		log.Printf("%s: Started %s %s for %s", time.Now().Format(LogTimeFormat), ctx.Req.Method, ctx.Req.RequestURI, ctx.RemoteAddr())

		rw := ctx.Resp.(ResponseWriter)
		ctx.Next()

		content := fmt.Sprintf("%s: Completed %s %s %v %s in %v", time.Now().Format(LogTimeFormat), ctx.Req.Method, ctx.Req.RequestURI, rw.Status(), http.StatusText(rw.Status()), time.Since(start))
		if ColorLog {
			switch rw.Status() {
			case 200, 201, 202:
				content = fmt.Sprintf("\033[1;32m%s\033[0m", content)
			case 301, 302:
				content = fmt.Sprintf("\033[1;37m%s\033[0m", content)
			case 304:
				content = fmt.Sprintf("\033[1;33m%s\033[0m", content)
			case 401, 403:
				content = fmt.Sprintf("\033[4;31m%s\033[0m", content)
			case 404:
				content = fmt.Sprintf("\033[1;31m%s\033[0m", content)
			case 500:
				content = fmt.Sprintf("\033[1;36m%s\033[0m", content)
			}
		}
		log.Println(content)
	}
}

func Logger ( ) Handler { return func ( ctx * Context , log * log . Logger ) { start := time . Now ( ) log . Printf ( " " , time . Now ( ) . Format ( LogTimeFormat ) , ctx . Req . Method , ctx . Req . RequestURI , ctx . RemoteAddr ( ) ) rw := ctx . Resp . ( ResponseWriter ) ctx . Next ( ) content := fmt . Sprintf ( " " , time . Now ( ) . Format ( LogTimeFormat ) , ctx . Req . Method , ctx . Req . RequestURI , rw . Status ( ) , http . StatusText ( rw . Status ( ) ) , time . Since ( start ) ) if ColorLog { switch rw . Status ( ) { case 200 , 201 , 202 : content = fmt . Sprintf ( " \033 \033 " , content ) case 301 , 302 : content = fmt . Sprintf ( " \033 \033 " , content ) case 304 : content = fmt . Sprintf ( " \033 \033 " , content ) case 401 , 403 : content = fmt . Sprintf ( " \033 \033 " , content ) case 404 : content = fmt . Sprintf ( " \033 \033 " , content ) case 500 : content = fmt . Sprintf ( " \033 \033 " , content ) } } log . Println ( content ) } }

// Logger returns a middleware handler that logs the request as it goes in and the response as it goes out.

Logger returns a middleware handler that logs the request as it goes in and the response as it goes out .


func NewTplFile(name string, data []byte, ext string) *TplFile {
	return &TplFile{name, data, ext}
}

func NewTplFile ( name string , data [ ] byte , ext string ) * TplFile { return & TplFile { name , data , ext } }

// NewTplFile cerates new template file with given name and data.

NewTplFile cerates new template file with given name and data .


func NewTemplateFileSystem(opt RenderOptions, omitData bool) TplFileSystem {
	fs := TplFileSystem{}
	fs.files = make([]TemplateFile, 0, 10)

	// Directories are composed in reverse order because later one overwrites previous ones,
	// so once found, we can directly jump out of the loop.
	dirs := make([]string, 0, len(opt.AppendDirectories)+1)
	for i := len(opt.AppendDirectories) - 1; i >= 0; i-- {
		dirs = append(dirs, opt.AppendDirectories[i])
	}
	dirs = append(dirs, opt.Directory)

	var err error
	for i := range dirs {
		// Skip ones that does not exists for symlink test,
		// but allow non-symlink ones added after start.
		if !com.IsExist(dirs[i]) {
			continue
		}

		dirs[i], err = filepath.EvalSymlinks(dirs[i])
		if err != nil {
			panic("EvalSymlinks(" + dirs[i] + "): " + err.Error())
		}
	}
	lastDir := dirs[len(dirs)-1]

	// We still walk the last (original) directory because it's non-sense we load templates not exist in original directory.
	if err = filepath.Walk(lastDir, func(path string, info os.FileInfo, err error) error {
		r, err := filepath.Rel(lastDir, path)
		if err != nil {
			return err
		}

		ext := GetExt(r)

		for _, extension := range opt.Extensions {
			if ext != extension {
				continue
			}

			var data []byte
			if !omitData {
				// Loop over candidates of directory, break out once found.
				// The file always exists because it's inside the walk function,
				// and read original file is the worst case.
				for i := range dirs {
					path = filepath.Join(dirs[i], r)
					if !com.IsFile(path) {
						continue
					}

					data, err = ioutil.ReadFile(path)
					if err != nil {
						return err
					}
					break
				}
			}

			name := filepath.ToSlash((r[0 : len(r)-len(ext)]))
			fs.files = append(fs.files, NewTplFile(name, data, ext))
		}

		return nil
	}); err != nil {
		panic("NewTemplateFileSystem: " + err.Error())
	}

	return fs
}

// NewTemplateFileSystem creates new template file system with given options.

NewTemplateFileSystem creates new template file system with given options .


func NewTemplateSet() *TemplateSet {
	return &TemplateSet{
		sets: make(map[string]*template.Template),
		dirs: make(map[string]string),
	}
}

func NewTemplateSet ( ) * TemplateSet { return & TemplateSet { sets : make ( map [ string ] * template . Template ) , dirs : make ( map [ string ] string ) , } }

// NewTemplateSet initializes a new empty template set.

NewTemplateSet initializes a new empty template set .


func GenerateETag(fileSize, fileName, modTime string) string {
	etag := fileSize + fileName + modTime
	return base64.StdEncoding.EncodeToString([]byte(etag))
}

func GenerateETag ( fileSize , fileName , modTime string ) string { etag := fileSize + fileName + modTime return base64 . StdEncoding . EncodeToString ( [ ] byte ( etag ) ) }

// GenerateETag generates an ETag based on size, filename and file modification time

GenerateETag generates an ETag based on size filename and file modification time


func Populate(values ...interface{}) error {
	var g Graph
	for _, v := range values {
		if err := g.Provide(&Object{Value: v}); err != nil {
			return err
		}
	}
	return g.Populate()
}

func Populate ( values ... interface { } ) error { var g Graph for _ , v := range values { if err := g . Provide ( & Object { Value : v } ) ; err != nil { return err } } return g . Populate ( ) }

// Populate is a short-hand for populating a graph with the given incomplete
// object values.

Populate is a short - hand for populating a graph with the given incomplete object values .


func (o *Object) String() string {
	var buf bytes.Buffer
	fmt.Fprint(&buf, o.reflectType)
	if o.Name != "" {
		fmt.Fprintf(&buf, " named %s", o.Name)
	}
	return buf.String()
}

func ( o * Object ) String ( ) string { var buf bytes . Buffer fmt . Fprint ( & buf , o . reflectType ) if o . Name != " " { fmt . Fprintf ( & buf , " " , o . Name ) } return buf . String ( ) }

// String representation suitable for human consumption.

String representation suitable for human consumption .


func (g *Graph) Provide(objects ...*Object) error {
	for _, o := range objects {
		o.reflectType = reflect.TypeOf(o.Value)
		o.reflectValue = reflect.ValueOf(o.Value)

		if o.Fields != nil {
			return fmt.Errorf(
				"fields were specified on object %s when it was provided",
				o,
			)
		}

		if o.Name == "" {
			if !isStructPtr(o.reflectType) {
				return fmt.Errorf(
					"expected unnamed object value to be a pointer to a struct but got type %s "+
						"with value %v",
					o.reflectType,
					o.Value,
				)
			}

			if !o.private {
				if g.unnamedType == nil {
					g.unnamedType = make(map[reflect.Type]bool)
				}

				if g.unnamedType[o.reflectType] {
					return fmt.Errorf(
						"provided two unnamed instances of type *%s.%s",
						o.reflectType.Elem().PkgPath(), o.reflectType.Elem().Name(),
					)
				}
				g.unnamedType[o.reflectType] = true
			}
			g.unnamed = append(g.unnamed, o)
		} else {
			if g.named == nil {
				g.named = make(map[string]*Object)
			}

			if g.named[o.Name] != nil {
				return fmt.Errorf("provided two instances named %s", o.Name)
			}
			g.named[o.Name] = o
		}

		if g.Logger != nil {
			if o.created {
				g.Logger.Debugf("created %s", o)
			} else if o.embedded {
				g.Logger.Debugf("provided embedded %s", o)
			} else {
				g.Logger.Debugf("provided %s", o)
			}
		}
	}
	return nil
}

func ( g * Graph ) Provide ( objects ... * Object ) error { for _ , o := range objects { o . reflectType = reflect . TypeOf ( o . Value ) o . reflectValue = reflect . ValueOf ( o . Value ) if o . Fields != nil { return fmt . Errorf ( " " , o , ) } if o . Name == " " { if ! isStructPtr ( o . reflectType ) { return fmt . Errorf ( " " + " " , o . reflectType , o . Value , ) } if ! o . private { if g . unnamedType == nil { g . unnamedType = make ( map [ reflect . Type ] bool ) } if g . unnamedType [ o . reflectType ] { return fmt . Errorf ( " " , o . reflectType . Elem ( ) . PkgPath ( ) , o . reflectType . Elem ( ) . Name ( ) , ) } g . unnamedType [ o . reflectType ] = true } g . unnamed = append ( g . unnamed , o ) } else { if g . named == nil { g . named = make ( map [ string ] * Object ) } if g . named [ o . Name ] != nil { return fmt . Errorf ( " " , o . Name ) } g . named [ o . Name ] = o } if g . Logger != nil { if o . created { g . Logger . Debugf ( " " , o ) } else if o . embedded { g . Logger . Debugf ( " " , o ) } else { g . Logger . Debugf ( " " , o ) } } } return nil }

// Provide objects to the Graph. The Object documentation describes
// the impact of various fields.

Provide objects to the Graph . The Object documentation describes the impact of various fields .


func (g *Graph) Populate() error {
	for _, o := range g.named {
		if o.Complete {
			continue
		}

		if err := g.populateExplicit(o); err != nil {
			return err
		}
	}

	// We append and modify our slice as we go along, so we don't use a standard
	// range loop, and do a single pass thru each object in our graph.
	i := 0
	for {
		if i == len(g.unnamed) {
			break
		}

		o := g.unnamed[i]
		i++

		if o.Complete {
			continue
		}

		if err := g.populateExplicit(o); err != nil {
			return err
		}
	}

	// A Second pass handles injecting Interface values to ensure we have created
	// all concrete types first.
	for _, o := range g.unnamed {
		if o.Complete {
			continue
		}

		if err := g.populateUnnamedInterface(o); err != nil {
			return err
		}
	}

	for _, o := range g.named {
		if o.Complete {
			continue
		}

		if err := g.populateUnnamedInterface(o); err != nil {
			return err
		}
	}

	return nil
}


func (g *Graph) Objects() []*Object {
	objects := make([]*Object, 0, len(g.unnamed)+len(g.named))
	for _, o := range g.unnamed {
		if !o.embedded {
			objects = append(objects, o)
		}
	}
	for _, o := range g.named {
		if !o.embedded {
			objects = append(objects, o)
		}
	}
	// randomize to prevent callers from relying on ordering
	for i := 0; i < len(objects); i++ {
		j := rand.Intn(i + 1)
		objects[i], objects[j] = objects[j], objects[i]
	}
	return objects
}

// Objects returns all known objects, named as well as unnamed. The returned
// elements are not in a stable order.

Objects returns all known objects named as well as unnamed . The returned elements are not in a stable order .


func newPubSub(client *pubsub.Client, name string, options *Options, store func(*points.Points)) (*PubSub, error) {
	logger := zapwriter.Logger(name)
	logger.Info("starting google pubsub receiver",
		zap.String("project", options.Project),
		zap.String("subscription", options.Subscription),
	)

	if options.Project == "" {
		return nil, fmt.Errorf("'project' must be specified")
	}

	ctx := context.Background()
	if client == nil {
		c, err := pubsub.NewClient(ctx, options.Project)
		if err != nil {
			return nil, err
		}
		client = c
	}

	sub := client.Subscription(options.Subscription)
	exists, err := sub.Exists(ctx)
	if err != nil {
		return nil, err
	}
	if !exists {
		// TODO: try to create subscription
		return nil, fmt.Errorf("subscription %s in project %s does not exist", options.Subscription, options.Project)
	}

	if options.ReceiverGoRoutines != 0 {
		sub.ReceiveSettings.NumGoroutines = options.ReceiverGoRoutines
	}
	if options.ReceiverMaxBytes != 0 {
		sub.ReceiveSettings.MaxOutstandingBytes = options.ReceiverMaxBytes
	}
	if options.ReceiverMaxMessages != 0 {
		sub.ReceiveSettings.MaxOutstandingMessages = options.ReceiverMaxMessages
	}

	// cancel() will be called to signal the subscription Receive() goroutines to finish and shutdown
	cctx, cancel := context.WithCancel(ctx)

	rcv := &PubSub{
		out:          store,
		name:         name,
		client:       client,
		cancel:       cancel,
		subscription: sub,
		logger:       logger,
		closed:       make(chan struct{}),
	}

	// Receive() will create goroutines as necessary to handle incoming messages. Reconnect
	// on error. Stop processing messages only if Stop() is called
	go func() {
		for {
			err := rcv.subscription.Receive(cctx, func(ctx context.Context, m *pubsub.Message) {
				rcv.handleMessage(m)
				m.Ack()
			})
			if err == context.Canceled {
				close(rcv.closed)
				rcv.Stop()
				break
			}
			if err != nil {
				rcv.logger.Error(err.Error())
			}
			time.Sleep(1 * time.Second)
		}
	}()

	return rcv, nil
}

// newPubSub returns a PubSub receiver. Optionally accepts a client to allow
// for injecting the fake for tests. If client is nil a real
// client connection to the google pubsub service will be attempted.

newPubSub returns a PubSub receiver . Optionally accepts a client to allow for injecting the fake for tests . If client is nil a real client connection to the google pubsub service will be attempted .


func (rcv *PubSub) Stat(send helper.StatCallback) {
	messagesReceived := atomic.LoadUint32(&rcv.messagesReceived)
	send("messagesReceived", float64(messagesReceived))

	metricsReceived := atomic.LoadUint32(&rcv.metricsReceived)
	send("metricsReceived", float64(metricsReceived))

	errors := atomic.LoadUint32(&rcv.errors)
	send("errors", float64(errors))

	if !rcv.statsAsCounters {
		atomic.AddUint32(&rcv.messagesReceived, -messagesReceived)
		atomic.AddUint32(&rcv.metricsReceived, -metricsReceived)
		atomic.AddUint32(&rcv.errors, -errors)
	}
}

func ( rcv * PubSub ) Stat ( send helper . StatCallback ) { messagesReceived := atomic . LoadUint32 ( & rcv . messagesReceived ) send ( " " , float64 ( messagesReceived ) ) metricsReceived := atomic . LoadUint32 ( & rcv . metricsReceived ) send ( " " , float64 ( metricsReceived ) ) errors := atomic . LoadUint32 ( & rcv . errors ) send ( " " , float64 ( errors ) ) if ! rcv . statsAsCounters { atomic . AddUint32 ( & rcv . messagesReceived , - messagesReceived ) atomic . AddUint32 ( & rcv . metricsReceived , - metricsReceived ) atomic . AddUint32 ( & rcv . errors , - errors ) } }

// Stat sends pubsub receiver's internal stats to specified callback

Stat sends pubsub receiver s internal stats to specified callback


func New(configFilename string) *App {
	app := &App{
		ConfigFilename: configFilename,
		Config:         NewConfig(),
		PromRegistry:   prometheus.NewPedanticRegistry(),
		exit:           make(chan bool),
	}

	return app
}

func New ( configFilename string ) * App { app := & App { ConfigFilename : configFilename , Config : NewConfig ( ) , PromRegistry : prometheus . NewPedanticRegistry ( ) , exit : make ( chan bool ) , } return app }


func (app *App) configure() error {
	var err error

	cfg, err := ReadConfig(app.ConfigFilename)
	if err != nil {
		return err
	}

	// carbon-cache prefix
	if hostname, err := os.Hostname(); err == nil {
		hostname = strings.Replace(hostname, ".", "_", -1)
		cfg.Common.GraphPrefix = strings.Replace(cfg.Common.GraphPrefix, "{host}", hostname, -1)
	} else {
		cfg.Common.GraphPrefix = strings.Replace(cfg.Common.GraphPrefix, "{host}", "localhost", -1)
	}

	if cfg.Whisper.Enabled {
		cfg.Whisper.Schemas, err = persister.ReadWhisperSchemas(cfg.Whisper.SchemasFilename)
		if err != nil {
			return err
		}

		if cfg.Whisper.AggregationFilename != "" {
			cfg.Whisper.Aggregation, err = persister.ReadWhisperAggregation(cfg.Whisper.AggregationFilename)
			if err != nil {
				return err
			}
		} else {
			cfg.Whisper.Aggregation = persister.NewWhisperAggregation()
		}
	}
	if !(cfg.Cache.WriteStrategy == "max" ||
		cfg.Cache.WriteStrategy == "sorted" ||
		cfg.Cache.WriteStrategy == "noop") {
		return fmt.Errorf("go-carbon support only \"max\", \"sorted\"  or \"noop\" write-strategy")
	}

	if cfg.Common.MetricEndpoint == "" {
		cfg.Common.MetricEndpoint = MetricEndpointLocal
	}

	if cfg.Common.MetricEndpoint != MetricEndpointLocal {
		u, err := url.Parse(cfg.Common.MetricEndpoint)

		if err != nil {
			return fmt.Errorf("common.metric-endpoint parse error: %s", err.Error())
		}

		if u.Scheme != "tcp" && u.Scheme != "udp" {
			return fmt.Errorf("common.metric-endpoint supports only tcp and udp protocols. %#v is unsupported", u.Scheme)
		}
	}

	app.Config = cfg

	return nil
}

func
(
app
*
App
)
configure
(
)
error
{
var
err
error
cfg
,
err
:=
ReadConfig
(
app
.
ConfigFilename
)
if
err
!=
{
return
err
}
// carbon-cache prefix
if
hostname
,
err
:=
os
.
Hostname
(
)
;
err
==
{
hostname
=
strings
.
Replace
(
hostname
,
"
"
,
"
"
,
1
)
cfg
.
Common
.
GraphPrefix
=
strings
.
Replace
(
cfg
.
Common
.
GraphPrefix
,
"
"
,
hostname
,
1
)
}
else
{
cfg
.
Common
.
GraphPrefix
=
strings
.
Replace
(
cfg
.
Common
.
GraphPrefix
,
"
"
,
"
"
,
1
)
}
if
cfg
.
Whisper
.
Enabled
{
cfg
.
Whisper
.
Schemas
,
err
=
persister
.
ReadWhisperSchemas
(
cfg
.
Whisper
.
SchemasFilename
)
if
err
!=
{
return
err
}
if
cfg
.
Whisper
.
AggregationFilename
!=
"
"
{
cfg
.
Whisper
.
Aggregation
,
err
=
persister
.
ReadWhisperAggregation
(
cfg
.
Whisper
.
AggregationFilename
)
if
err
!=
{
return
err
}
}
else
{
cfg
.
Whisper
.
Aggregation
=
persister
.
NewWhisperAggregation
(
)
}
}
if
!
(
cfg
.
Cache
.
WriteStrategy
==
"
"
||
cfg
.
Cache
.
WriteStrategy
==
"
"
||
cfg
.
Cache
.
WriteStrategy
==
"
"
)
{
return
fmt
.
Errorf
(
"
\"
\"
\"
\"
\"
\"
"
)
}
if
cfg
.
Common
.
MetricEndpoint
==
"
"
{
cfg
.
Common
.
MetricEndpoint
=
MetricEndpointLocal
}
if
cfg
.
Common
.
MetricEndpoint
!=
MetricEndpointLocal
{
u
,
err
:=
url
.
Parse
(
cfg
.
Common
.
MetricEndpoint
)
if
err
!=
{
return
fmt
.
Errorf
(
"
"
,
err
.
Error
(
)
)
}
if
u
.
Scheme
!=
"
"
&&
u
.
Scheme
!=
"
"
{
return
fmt
.
Errorf
(
"
"
,
u
.
Scheme
)
}
}
app
.
Config
=
cfg
return
}

// configure loads config from config file, schemas.conf, aggregation.conf

configure loads config from config file schemas . conf aggregation . conf


func (app *App) ParseConfig() error {
	app.Lock()
	defer app.Unlock()

	err := app.configure()

	if app.PromRegisterer == nil {
		app.PromRegisterer = prometheus.WrapRegistererWith(
			prometheus.Labels(app.Config.Prometheus.Labels),
			app.PromRegistry,
		)
	}

	return err
}

func ( app * App ) ParseConfig ( ) error { app . Lock ( ) defer app . Unlock ( ) err := app . configure ( ) if app . PromRegisterer == nil { app . PromRegisterer = prometheus . WrapRegistererWith ( prometheus . Labels ( app . Config . Prometheus . Labels ) , app . PromRegistry , ) } return err }

// ParseConfig loads config from config file, schemas.conf, aggregation.conf

ParseConfig loads config from config file schemas . conf aggregation . conf


func (app *App) ReloadConfig() error {
	app.Lock()
	defer app.Unlock()

	var err error
	if err = app.configure(); err != nil {
		return err
	}

	runtime.GOMAXPROCS(app.Config.Common.MaxCPU)

	app.Cache.SetMaxSize(app.Config.Cache.MaxSize)
	app.Cache.SetWriteStrategy(app.Config.Cache.WriteStrategy)
	app.Cache.SetTagsEnabled(app.Config.Tags.Enabled)

	if app.Persister != nil {
		app.Persister.Stop()
		app.Persister = nil
	}

	if app.Tags != nil {
		app.Tags.Stop()
		app.Tags = nil
	}

	app.startPersister()

	if app.Collector != nil {
		app.Collector.Stop()
		app.Collector = nil
	}

	app.Collector = NewCollector(app)

	return nil
}

func ( app * App ) ReloadConfig ( ) error { app . Lock ( ) defer app . Unlock ( ) var err error if err = app . configure ( ) ; err != nil { return err } runtime . GOMAXPROCS ( app . Config . Common . MaxCPU ) app . Cache . SetMaxSize ( app . Config . Cache . MaxSize ) app . Cache . SetWriteStrategy ( app . Config . Cache . WriteStrategy ) app . Cache . SetTagsEnabled ( app . Config . Tags . Enabled ) if app . Persister != nil { app . Persister . Stop ( ) app . Persister = nil } if app . Tags != nil { app . Tags . Stop ( ) app . Tags = nil } app . startPersister ( ) if app . Collector != nil { app . Collector . Stop ( ) app . Collector = nil } app . Collector = NewCollector ( app ) return nil }

// ReloadConfig reloads some settings from config


func (app *App) stopListeners() {
	logger := zapwriter.Logger("app")

	if app.Api != nil {
		app.Api.Stop()
		app.Api = nil
		logger.Debug("api stopped")
	}

	if app.CarbonLink != nil {
		app.CarbonLink.Stop()
		app.CarbonLink = nil
		logger.Debug("carbonlink stopped")
	}

	if app.Carbonserver != nil {
		carbonserver := app.Carbonserver
		go func() {
			carbonserver.Stop()
			logger.Debug("carbonserver stopped")
		}()
		app.Carbonserver = nil
	}

	if app.Receivers != nil {
		for i := 0; i < len(app.Receivers); i++ {
			app.Receivers[i].Stop()
			logger.Debug("receiver stopped", zap.String("name", app.Receivers[i].Name))
		}
		app.Receivers = nil
	}
}

func ( app * App ) stopListeners ( ) { logger := zapwriter . Logger ( " " ) if app . Api != nil { app . Api . Stop ( ) app . Api = nil logger . Debug ( " " ) } if app . CarbonLink != nil { app . CarbonLink . Stop ( ) app . CarbonLink = nil logger . Debug ( " " ) } if app . Carbonserver != nil { carbonserver := app . Carbonserver go func ( ) { carbonserver . Stop ( ) logger . Debug ( " " ) } ( ) app . Carbonserver = nil } if app . Receivers != nil { for i := 0 ; i < len ( app . Receivers ) ; i ++ { app . Receivers [ i ] . Stop ( ) logger . Debug ( " " , zap . String ( " " , app . Receivers [ i ] . Name ) ) } app . Receivers = nil } }


func (o *Offset) MarshalText() ([]byte, error) {
	switch *o {
	case OffsetNewest:
		return []byte("newest"), nil
	case OffsetOldest:
		return []byte("oldest"), nil
	}
	return []byte(fmt.Sprintf("%v", *o)), nil
}

func ( o * Offset ) MarshalText ( ) ( [ ] byte , error ) { switch * o { case OffsetNewest : return [ ] byte ( " " ) , nil case OffsetOldest : return [ ] byte ( " " ) , nil } return [ ] byte ( fmt . Sprintf ( " " , * o ) ) , nil }

// MarshalText marshals offset. It's used to handle two special cases "newest" and "oldest".

MarshalText marshals offset . It s used to handle two special cases newest and oldest .


func (o *Offset) UnmarshalText(text []byte) error {
	offsetName := string(text)

	switch strings.ToLower(offsetName) {
	case "newest":
		*o = OffsetNewest
	case "oldest":
		*o = OffsetOldest
	default:
		d, err := time.ParseDuration(offsetName)
		if err != nil {
			return err
		}
		*o = Offset(time.Now().Add(d).UnixNano())
	}
	return nil
}

func ( o * Offset ) UnmarshalText ( text [ ] byte ) error { offsetName := string ( text ) switch strings . ToLower ( offsetName ) { case " " : * o = OffsetNewest case " " : * o = OffsetOldest default : d , err := time . ParseDuration ( offsetName ) if err != nil { return err } * o = Offset ( time . Now ( ) . Add ( d ) . UnixNano ( ) ) } return nil }

// UnmarshalText unmarshals text to offset. It handles "newest" and "oldest", oterwise fallbacks to time.ParseDuration.

UnmarshalText unmarshals text to offset . It handles newest and oldest oterwise fallbacks to time . ParseDuration .


func (p *Protocol) MarshalText() ([]byte, error) {
	switch *p {
	case ProtocolPlain:
		return []byte("plain"), nil
	case ProtocolProtobuf:
		return []byte("protobuf"), nil
	case ProtocolPickle:
		return []byte("pickle"), nil
	}
	return nil, fmt.Errorf("Unsupported offset type %v, supported offsets: %v", p, supportedProtocols)
}

func ( p * Protocol ) MarshalText ( ) ( [ ] byte , error ) { switch * p { case ProtocolPlain : return [ ] byte ( " " ) , nil case ProtocolProtobuf : return [ ] byte ( " " ) , nil case ProtocolPickle : return [ ] byte ( " " ) , nil } return nil , fmt . Errorf ( " " , p , supportedProtocols ) }

// MarshalText converts internal enum-like representation of protocol to a text

MarshalText converts internal enum - like representation of protocol to a text


func (p *Protocol) UnmarshalText(text []byte) error {
	protocolName := string(text)

	switch strings.ToLower(protocolName) {
	case "plain":
		*p = ProtocolPlain
	case "protobuf":
		*p = ProtocolProtobuf
	case "pickle":
		*p = ProtocolPickle
	default:
		return fmt.Errorf("Unsupported protocol type %v, supported: %v", protocolName, supportedProtocols)
	}
	return nil
}

func ( p * Protocol ) UnmarshalText ( text [ ] byte ) error { protocolName := string ( text ) switch strings . ToLower ( protocolName ) { case " " : * p = ProtocolPlain case " " : * p = ProtocolProtobuf case " " : * p = ProtocolPickle default : return fmt . Errorf ( " " , protocolName , supportedProtocols ) } return nil }

// UnmarshalText converts text from config file to a enum.

UnmarshalText converts text from config file to a enum .


func (d *Duration) UnmarshalText(text []byte) error {
	var err error
	d.Duration, err = time.ParseDuration(string(text))
	return err
}

func ( d * Duration ) UnmarshalText ( text [ ] byte ) error { var err error d . Duration , err = time . ParseDuration ( string ( text ) ) return err }


func NewOptions() *Options {
	return &Options{
		Brokers:           []string{"localhost:9092"},
		Topic:             "graphite",
		Partition:         0,
		Protocol:          ProtocolPlain,
		InitialOffset:     OffsetOldest,
		StateSaveInterval: &Duration{Duration: 60 * time.Second},
		ReconnectInterval: &Duration{Duration: 60 * time.Second},
		FetchInterval:     &Duration{Duration: 250 * time.Millisecond},
		KafkaVersion:      "0.11.0.0",
	}
}

func NewOptions ( ) * Options { return & Options { Brokers : [ ] string { " " } , Topic : " " , Partition : 0 , Protocol : ProtocolPlain , InitialOffset : OffsetOldest , StateSaveInterval : & Duration { Duration : 60 * time . Second } , ReconnectInterval : & Duration { Duration : 60 * time . Second } , FetchInterval : & Duration { Duration : 250 * time . Millisecond } , KafkaVersion : " " , } }

// NewOptions returns Options struct filled with default values.

NewOptions returns Options struct filled with default values .


func (rcv *Kafka) Stat(send helper.StatCallback) {
	metricsReceived := atomic.LoadUint64(&rcv.metricsReceived)
	send("metricsReceived", float64(metricsReceived))

	errors := atomic.LoadUint64(&rcv.errors)
	send("errors", float64(errors))

	if !rcv.statsAsCounters {
		atomic.AddUint64(&rcv.metricsReceived, -metricsReceived)
		atomic.AddUint64(&rcv.errors, -errors)
	}
}

func ( rcv * Kafka ) Stat ( send helper . StatCallback ) { metricsReceived := atomic . LoadUint64 ( & rcv . metricsReceived ) send ( " " , float64 ( metricsReceived ) ) errors := atomic . LoadUint64 ( & rcv . errors ) send ( " " , float64 ( errors ) ) if ! rcv . statsAsCounters { atomic . AddUint64 ( & rcv . metricsReceived , - metricsReceived ) atomic . AddUint64 ( & rcv . errors , - errors ) } }

// Stat sends kafka receiver's internal stats to specified callback

Stat sends kafka receiver s internal stats to specified callback


func New() *Cache {
	c := &Cache{
		data:          make([]*Shard, shardCount),
		writeStrategy: Noop,
	}

	for i := 0; i < shardCount; i++ {
		c.data[i] = &Shard{
			items:        make(map[string]*points.Points),
			notConfirmed: make([]*points.Points, 4),
		}
	}

	settings := cacheSettings{
		maxSize:     1000000,
		tagsEnabled: false,
		xlog:        nil,
	}

	c.settings.Store(&settings)

	c.writeoutQueue = NewWriteoutQueue(c)
	return c
}

func New ( ) * Cache { c := & Cache { data : make ( [ ] * Shard , shardCount ) , writeStrategy : Noop , } for i := 0 ; i < shardCount ; i ++ { c . data [ i ] = & Shard { items : make ( map [ string ] * points . Points ) , notConfirmed : make ( [ ] * points . Points , 4 ) , } } settings := cacheSettings { maxSize : 1000000 , tagsEnabled : false , xlog : nil , } c . settings . Store ( & settings ) c . writeoutQueue = NewWriteoutQueue ( c ) return c }


func (c *Cache) SetMaxSize(maxSize uint32) {
	s := c.settings.Load().(*cacheSettings)
	newSettings := *s
	newSettings.maxSize = int32(maxSize)
	c.settings.Store(&newSettings)
}

func ( c * Cache ) SetMaxSize ( maxSize uint32 ) { s := c . settings . Load ( ) . ( * cacheSettings ) newSettings := * s newSettings . maxSize = int32 ( maxSize ) c . settings . Store ( & newSettings ) }


func (c *Cache) GetShard(key string) *Shard {
	// @TODO: remove type casts?
	return c.data[uint(fnv32(key))%uint(shardCount)]
}

func
(
c
*
Cache
)
GetShard
(
key
string
)
*
Shard
{
// @TODO: remove type casts?
return
c
.
data
[
uint
(
fnv32
(
key
)
)
%
uint
(
shardCount
)
]
}

// GetShard returns shard under given key


func (c *Cache) Add(p *points.Points) {
	s := c.settings.Load().(*cacheSettings)

	if s.xlog != nil {
		p.WriteTo(s.xlog)
		return
	}

	if s.tagsEnabled {
		var err error
		p.Metric, err = tags.Normalize(p.Metric)
		if err != nil {
			atomic.AddUint32(&c.stat.tagsNormalizeErrors, 1)
			return
		}
	}

	// Get map shard.
	count := len(p.Data)

	if s.maxSize > 0 && c.Size() > s.maxSize {
		atomic.AddUint32(&c.stat.overflowCnt, uint32(count))
		return
	}

	shard := c.GetShard(p.Metric)

	shard.Lock()
	if values, exists := shard.items[p.Metric]; exists {
		values.Data = append(values.Data, p.Data...)
	} else {
		shard.items[p.Metric] = p
	}
	shard.Unlock()

	atomic.AddInt32(&c.stat.size, int32(count))
}

func
(
c
*
Cache
)
Add
(
p
*
points
.
Points
)
{
s
:=
c
.
settings
.
Load
(
)
.
(
*
cacheSettings
)
if
s
.
xlog
!=
{
p
.
WriteTo
(
s
.
xlog
)
return
}
if
s
.
tagsEnabled
{
var
err
error
p
.
Metric
,
err
=
tags
.
Normalize
(
p
.
Metric
)
if
err
!=
{
atomic
.
AddUint32
(
&
c
.
stat
.
tagsNormalizeErrors
,
1
)
return
}
}
// Get map shard.
count
:=
len
(
p
.
Data
)
if
s
.
maxSize
>
0
&&
c
.
Size
(
)
>
s
.
maxSize
{
atomic
.
AddUint32
(
&
c
.
stat
.
overflowCnt
,
uint32
(
count
)
)
return
}
shard
:=
c
.
GetShard
(
p
.
Metric
)
shard
.
Lock
(
)
if
values
,
exists
:=
shard
.
items
[
p
.
Metric
]
;
exists
{
values
.
Data
=
append
(
values
.
Data
,
p
.
Data
...
)
}
else
{
shard
.
items
[
p
.
Metric
]
=
p
}
shard
.
Unlock
(
)
atomic
.
AddInt32
(
&
c
.
stat
.
size
,
int32
(
count
)
)
}

// Sets the given value under the specified key.

Sets the given value under the specified key .


func (c *Cache) Pop(key string) (p *points.Points, exists bool) {
	// Try to get shard.
	shard := c.GetShard(key)
	shard.Lock()
	p, exists = shard.items[key]
	delete(shard.items, key)
	shard.Unlock()

	if exists {
		atomic.AddInt32(&c.stat.size, -int32(len(p.Data)))
	}

	return p, exists
}

func
(
c
*
Cache
)
Pop
(
key
string
)
(
p
*
points
.
Points
,
exists
bool
)
{
// Try to get shard.
shard
:=
c
.
GetShard
(
key
)
shard
.
Lock
(
)
p
,
exists
=
shard
.
items
[
key
]
delete
(
shard
.
items
,
key
)
shard
.
Unlock
(
)
if
exists
{
atomic
.
AddInt32
(
&
c
.
stat
.
size
,
int32
(
len
(
p
.
Data
)
)
)
}
return
p
,
exists
}

// Pop removes an element from the map and returns it


func ParseCarbonlinkRequest(d []byte) (*CarbonlinkRequest, error) {

	if !(expectBytes(&d, []byte("\x80\x02}")) && pickleMaybeMemo(&d) && expectBytes(&d, []byte("("))) {
		return nil, badErr
	}

	req := NewCarbonlinkRequest()

	var Metric, Type string
	var ok bool

	if expectBytes(&d, []byte("U\x06metric")) {
		if !pickleMaybeMemo(&d) {
			return nil, badErr
		}
		if Metric, ok = pickleGetStr(&d); !ok {
			return nil, badErr
		}

		if !(pickleMaybeMemo(&d) && expectBytes(&d, []byte("U\x04type")) && pickleMaybeMemo(&d)) {
			return nil, badErr
		}

		if Type, ok = pickleGetStr(&d); !ok {
			return nil, badErr
		}

		if !pickleMaybeMemo(&d) {
			return nil, badErr
		}

		req.Metric = Metric
		req.Type = Type
	} else if expectBytes(&d, []byte("U\x04type")) {
		if !pickleMaybeMemo(&d) {
			return nil, badErr
		}

		if Type, ok = pickleGetStr(&d); !ok {
			return nil, badErr
		}

		if !(pickleMaybeMemo(&d) && expectBytes(&d, []byte("U\x06metric")) && pickleMaybeMemo(&d)) {
			return nil, badErr
		}

		if Metric, ok = pickleGetStr(&d); !ok {
			return nil, badErr
		}

		if !pickleMaybeMemo(&d) {
			return nil, badErr
		}

		req.Metric = Metric
		req.Type = Type
	} else {
		return nil, badErr
	}

	return req, nil
}

func ParseCarbonlinkRequest ( d [ ] byte ) ( * CarbonlinkRequest , error ) { if ! ( expectBytes ( & d , [ ] byte ( " \x80 \x02 " ) ) && pickleMaybeMemo ( & d ) && expectBytes ( & d , [ ] byte ( " " ) ) ) { return nil , badErr } req := NewCarbonlinkRequest ( ) var Metric , Type string var ok bool if expectBytes ( & d , [ ] byte ( " \x06 " ) ) { if ! pickleMaybeMemo ( & d ) { return nil , badErr } if Metric , ok = pickleGetStr ( & d ) ; ! ok { return nil , badErr } if ! ( pickleMaybeMemo ( & d ) && expectBytes ( & d , [ ] byte ( " \x04 " ) ) && pickleMaybeMemo ( & d ) ) { return nil , badErr } if Type , ok = pickleGetStr ( & d ) ; ! ok { return nil , badErr } if ! pickleMaybeMemo ( & d ) { return nil , badErr } req . Metric = Metric req . Type = Type } else if expectBytes ( & d , [ ] byte ( " \x04 " ) ) { if ! pickleMaybeMemo ( & d ) { return nil , badErr } if Type , ok = pickleGetStr ( & d ) ; ! ok { return nil , badErr } if ! ( pickleMaybeMemo ( & d ) && expectBytes ( & d , [ ] byte ( " \x06 " ) ) && pickleMaybeMemo ( & d ) ) { return nil , badErr } if Metric , ok = pickleGetStr ( & d ) ; ! ok { return nil , badErr } if ! pickleMaybeMemo ( & d ) { return nil , badErr } req . Metric = Metric req . Type = Type } else { return nil , badErr } return req , nil }

// ParseCarbonlinkRequest from pickle encoded data


func NewCarbonlinkListener(cache *Cache) *CarbonlinkListener {
	return &CarbonlinkListener{
		cache:       cache,
		readTimeout: 30 * time.Second,
	}
}

func NewCarbonlinkListener ( cache * Cache ) * CarbonlinkListener { return & CarbonlinkListener { cache : cache , readTimeout : 30 * time . Second , } }

// NewCarbonlinkListener create new instance of CarbonlinkListener


func OnePoint(metric string, value float64, timestamp int64) *Points {
	return &Points{
		Metric: metric,
		Data: []Point{
			Point{
				Value:     value,
				Timestamp: timestamp,
			},
		},
	}
}

func OnePoint ( metric string , value float64 , timestamp int64 ) * Points { return & Points { Metric : metric , Data : [ ] Point { Point { Value : value , Timestamp : timestamp , } , } , } }

// OnePoint create Points instance with single point


func NowPoint(metric string, value float64) *Points {
	return OnePoint(metric, value, time.Now().Unix())
}

func NowPoint ( metric string , value float64 ) * Points { return OnePoint ( metric , value , time . Now ( ) . Unix ( ) ) }

// NowPoint create OnePoint with now timestamp


func (p *Points) Copy() *Points {
	return &Points{
		Metric: p.Metric,
		Data:   p.Data,
	}
}

func ( p * Points ) Copy ( ) * Points { return & Points { Metric : p . Metric , Data : p . Data , } }


func ParseText(line string) (*Points, error) {

	row := strings.Split(strings.Trim(line, "\n \t\r"), " ")
	if len(row) != 3 {
		return nil, fmt.Errorf("bad message: %#v", line)
	}

	// 0x2e == ".". Or use split? @TODO: benchmark
	// if strings.Contains(row[0], "..") || row[0][0] == 0x2e || row[0][len(row)-1] == 0x2e {
	// 	return nil, fmt.Errorf("bad message: %#v", line)
	// }

	value, err := strconv.ParseFloat(row[1], 64)

	if err != nil || math.IsNaN(value) {
		return nil, fmt.Errorf("bad message: %#v", line)
	}

	tsf, err := strconv.ParseFloat(row[2], 64)

	if err != nil || math.IsNaN(tsf) {
		return nil, fmt.Errorf("bad message: %#v", line)
	}

	// 315522000 == "1980-01-01 00:00:00"
	// if tsf < 315532800 {
	// 	return nil, fmt.Errorf("bad message: %#v", line)
	// }

	// 4102444800 = "2100-01-01 00:00:00"
	// Hello people from the future
	// if tsf > 4102444800 {
	// 	return nil, fmt.Errorf("bad message: %#v", line)
	// }

	return OnePoint(row[0], value, int64(tsf)), nil
}

// ParseText parse text protocol Point
//  host.Point.value 42 1422641531\n

ParseText parse text protocol Point host . Point . value 42 1422641531 \ n


func (p *Points) Eq(other *Points) bool {
	if other == nil {
		return false
	}
	if p.Metric != other.Metric {
		return false
	}
	if p.Data == nil && other.Data == nil {
		return true
	}
	if (p.Data == nil || other.Data == nil) && (p.Data != nil || other.Data != nil) {
		return false
	}
	if len(p.Data) != len(other.Data) {
		return false
	}
	for i := 0; i < len(p.Data); i++ {
		if p.Data[i].Value != other.Data[i].Value {
			return false
		}
		if p.Data[i].Timestamp != other.Data[i].Timestamp {
			return false
		}
	}
	return true
}

func ( p * Points ) Eq ( other * Points ) bool { if other == nil { return false } if p . Metric != other . Metric { return false } if p . Data == nil && other . Data == nil { return true } if ( p . Data == nil || other . Data == nil ) && ( p . Data != nil || other . Data != nil ) { return false } if len ( p . Data ) != len ( other . Data ) { return false } for i := 0 ; i < len ( p . Data ) ; i ++ { if p . Data [ i ] . Value != other . Data [ i ] . Value { return false } if p . Data [ i ] . Timestamp != other . Data [ i ] . Timestamp { return false } } return true }


func (s WhisperSchemas) Match(metric string) (Schema, bool) {
	for _, schema := range s {
		if schema.Pattern.MatchString(metric) {
			return schema, true
		}
	}
	return Schema{}, false
}

func ( s WhisperSchemas ) Match ( metric string ) ( Schema , bool ) { for _ , schema := range s { if schema . Pattern . MatchString ( metric ) { return schema , true } } return Schema { } , false }

// Match finds the schema for metric or returns false if none found


func ParseRetentionDefs(retentionDefs string) (whisper.Retentions, error) {
	retentions := make(whisper.Retentions, 0)
	for _, retentionDef := range strings.Split(retentionDefs, ",") {
		retentionDef = strings.TrimSpace(retentionDef)
		parts := strings.Split(retentionDef, ":")
		if len(parts) != 2 {
			return nil, fmt.Errorf("bad retentions spec %q", retentionDef)
		}

		// try old format
		val1, err1 := strconv.ParseInt(parts[0], 10, 0)
		val2, err2 := strconv.ParseInt(parts[1], 10, 0)

		if err1 == nil && err2 == nil {
			retention := whisper.NewRetention(int(val1), int(val2))
			retentions = append(retentions, &retention)
			continue
		}

		// try new format
		retention, err := whisper.ParseRetentionDef(retentionDef)
		if err != nil {
			return nil, err
		}
		retentions = append(retentions, retention)
	}
	return retentions, nil
}

func
ParseRetentionDefs
(
retentionDefs
string
)
(
whisper
.
Retentions
,
error
)
{
retentions
:=
make
(
whisper
.
Retentions
,
0
)
for
_
,
retentionDef
:=
range
strings
.
Split
(
retentionDefs
,
"
"
)
{
retentionDef
=
strings
.
TrimSpace
(
retentionDef
)
parts
:=
strings
.
Split
(
retentionDef
,
"
"
)
if
len
(
parts
)
!=
2
{
return
,
fmt
.
Errorf
(
"
"
,
retentionDef
)
}
// try old format
val1
,
err1
:=
strconv
.
ParseInt
(
parts
[
0
]
,
10
,
0
)
val2
,
err2
:=
strconv
.
ParseInt
(
parts
[
1
]
,
10
,
0
)
if
err1
==
&&
err2
==
{
retention
:=
whisper
.
NewRetention
(
int
(
val1
)
,
int
(
val2
)
)
retentions
=
append
(
retentions
,
&
retention
)
continue
}
// try new format
retention
,
err
:=
whisper
.
ParseRetentionDef
(
retentionDef
)
if
err
!=
{
return
,
err
}
retentions
=
append
(
retentions
,
retention
)
}
return
retentions
,
}

// ParseRetentionDefs parses retention definitions into a Retentions structure


func (app *App) RestoreFromFile(filename string, storeFunc func(*points.Points)) error {
	var pointsCount int
	startTime := time.Now()

	logger := zapwriter.Logger("restore").With(zap.String("filename", filename))
	logger.Info("restore started")

	defer func() {
		logger.Info("restore finished",
			zap.Int("points", pointsCount),
			zap.Duration("runtime", time.Since(startTime)),
		)
	}()

	err := points.ReadFromFile(filename, func(p *points.Points) {
		pointsCount += len(p.Data)
		storeFunc(p)
	})

	return err
}

func ( app * App ) RestoreFromFile ( filename string , storeFunc func ( * points . Points ) ) error { var pointsCount int startTime := time . Now ( ) logger := zapwriter . Logger ( " " ) . With ( zap . String ( " " , filename ) ) logger . Info ( " " ) defer func ( ) { logger . Info ( " " , zap . Int ( " " , pointsCount ) , zap . Duration ( " " , time . Since ( startTime ) ) , ) } ( ) err := points . ReadFromFile ( filename , func ( p * points . Points ) { pointsCount += len ( p . Data ) storeFunc ( p ) } ) return err }

// RestoreFromFile read and parse data from single file


func (app *App) RestoreFromDir(dumpDir string, storeFunc func(*points.Points)) {
	startTime := time.Now()

	logger := zapwriter.Logger("restore").With(zap.String("dir", dumpDir))

	defer func() {
		logger.Info("restore finished",
			zap.Duration("runtime", time.Since(startTime)),
		)
	}()

	files, err := ioutil.ReadDir(dumpDir)
	if err != nil {
		logger.Error("readdir failed", zap.Error(err))
		return
	}

	// read files and lazy sorting
	list := make([]string, 0)

FilesLoop:
	for _, file := range files {
		if file.IsDir() {
			continue
		}

		r := strings.Split(file.Name(), ".")
		if len(r) < 3 { // {input,cache}.pid.nanotimestamp(.+)?
			continue
		}

		var fileWithSortPrefix string

		switch r[0] {
		case "cache":
			fileWithSortPrefix = fmt.Sprintf("%s_%s:%s", r[2], "1", file.Name())
		case "input":
			fileWithSortPrefix = fmt.Sprintf("%s_%s:%s", r[2], "2", file.Name())
		default:
			continue FilesLoop
		}

		list = append(list, fileWithSortPrefix)
	}

	if len(list) == 0 {
		logger.Info("nothing for restore")
		return
	}

	sort.Strings(list)

	for index, fileWithSortPrefix := range list {
		list[index] = strings.SplitN(fileWithSortPrefix, ":", 2)[1]
	}

	logger.Info("start restore", zap.Int("files", len(list)))

	for _, fn := range list {
		filename := path.Join(dumpDir, fn)
		app.RestoreFromFile(filename, storeFunc)

		err = os.Remove(filename)
		if err != nil {
			logger.Error("remove failed", zap.String("filename", filename), zap.Error(err))
		}
	}
}

func
(
app
*
App
)
RestoreFromDir
(
dumpDir
string
,
storeFunc
func
(
*
points
.
Points
)
)
{
startTime
:=
time
.
Now
(
)
logger
:=
zapwriter
.
Logger
(
"
"
)
.
With
(
zap
.
String
(
"
"
,
dumpDir
)
)
defer
func
(
)
{
logger
.
Info
(
"
"
,
zap
.
Duration
(
"
"
,
time
.
Since
(
startTime
)
)
,
)
}
(
)
files
,
err
:=
ioutil
.
ReadDir
(
dumpDir
)
if
err
!=
{
logger
.
Error
(
"
"
,
zap
.
Error
(
err
)
)
return
}
// read files and lazy sorting
list
:=
make
(
[
]
string
,
0
)
FilesLoop
:
for
_
,
file
:=
range
files
{
if
file
.
IsDir
(
)
{
continue
}
r
:=
strings
.
Split
(
file
.
Name
(
)
,
"
"
)
if
len
(
r
)
<
3
{
// {input,cache}.pid.nanotimestamp(.+)?
continue
}
var
fileWithSortPrefix
string
switch
r
[
0
]
{
case
"
"
:
fileWithSortPrefix
=
fmt
.
Sprintf
(
"
"
,
r
[
2
]
,
"
"
,
file
.
Name
(
)
)
case
"
"
:
fileWithSortPrefix
=
fmt
.
Sprintf
(
"
"
,
r
[
2
]
,
"
"
,
file
.
Name
(
)
)
default
:
continue
FilesLoop
}
list
=
append
(
list
,
fileWithSortPrefix
)
}
if
len
(
list
)
==
0
{
logger
.
Info
(
"
"
)
return
}
sort
.
Strings
(
list
)
for
index
,
fileWithSortPrefix
:=
range
list
{
list
[
index
]
=
strings
.
SplitN
(
fileWithSortPrefix
,
"
"
,
2
)
[
1
]
}
logger
.
Info
(
"
"
,
zap
.
Int
(
"
"
,
len
(
list
)
)
)
for
_
,
fn
:=
range
list
{
filename
:=
path
.
Join
(
dumpDir
,
fn
)
app
.
RestoreFromFile
(
filename
,
storeFunc
)
err
=
os
.
Remove
(
filename
)
if
err
!=
{
logger
.
Error
(
"
"
,
zap
.
String
(
"
"
,
filename
)
,
zap
.
Error
(
err
)
)
}
}
}

// RestoreFromDir cache and input dumps from disk to memory


func (app *App) Restore(storeFunc func(*points.Points), path string, rps int) {
	if rps > 0 {
		ticker := persister.NewThrottleTicker(rps)
		defer ticker.Stop()

		throttledStoreFunc := func(p *points.Points) {
			for i := 0; i < len(p.Data); i++ {
				<-ticker.C
			}
			storeFunc(p)
		}

		app.RestoreFromDir(path, throttledStoreFunc)
	} else {
		app.RestoreFromDir(path, storeFunc)
	}
}

func ( app * App ) Restore ( storeFunc func ( * points . Points ) , path string , rps int ) { if rps > 0 { ticker := persister . NewThrottleTicker ( rps ) defer ticker . Stop ( ) throttledStoreFunc := func ( p * points . Points ) { for i := 0 ; i < len ( p . Data ) ; i ++ { <- ticker . C } storeFunc ( p ) } app . RestoreFromDir ( path , throttledStoreFunc ) } else { app . RestoreFromDir ( path , storeFunc ) } }


func Root(t *testing.T, callback func(dir string)) {
	tmpDir, err := ioutil.TempDir("", "")
	if err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := os.RemoveAll(tmpDir); err != nil {
			t.Fatal(err)
		}
	}()

	callback(tmpDir)
}

func Root ( t * testing . T , callback func ( dir string ) ) { tmpDir , err := ioutil . TempDir ( " " , " " ) if err != nil { t . Fatal ( err ) } defer func ( ) { if err := os . RemoveAll ( tmpDir ) ; err != nil { t . Fatal ( err ) } } ( ) callback ( tmpDir ) }


func (q *Queue) delete(key []byte) {
	err := q.db.Delete([]byte(key), nil)
	atomic.AddUint32(&q.stat.deleteCount, 1)
	if err != nil {
		atomic.AddUint32(&q.stat.deleteErrors, 1)
		q.logger.Error("delete from queue database failed", zap.Error(err))
	}
}

func ( q * Queue ) delete ( key [ ] byte ) { err := q . db . Delete ( [ ] byte ( key ) , nil ) atomic . AddUint32 ( & q . stat . deleteCount , 1 ) if err != nil { atomic . AddUint32 ( & q . stat . deleteErrors , 1 ) q . logger . Error ( " " , zap . Error ( err ) ) } }


func NewWhisper(
	rootPath string,
	schemas WhisperSchemas,
	aggregation *WhisperAggregation,
	recv func(chan bool) string,
	pop func(string) (*points.Points, bool),
	confirm func(*points.Points)) *Whisper {

	return &Whisper{
		recv:                recv,
		pop:                 pop,
		confirm:             confirm,
		schemas:             schemas,
		aggregation:         aggregation,
		workersCount:        1,
		rootPath:            rootPath,
		maxUpdatesPerSecond: 0,
		logger:              zapwriter.Logger("persister"),
		createLogger:        zapwriter.Logger("whisper:new"),
	}
}

func NewWhisper ( rootPath string , schemas WhisperSchemas , aggregation * WhisperAggregation , recv func ( chan bool ) string , pop func ( string ) ( * points . Points , bool ) , confirm func ( * points . Points ) ) * Whisper { return & Whisper { recv : recv , pop : pop , confirm : confirm , schemas : schemas , aggregation : aggregation , workersCount : 1 , rootPath : rootPath , maxUpdatesPerSecond : 0 , logger : zapwriter . Logger ( " " ) , createLogger : zapwriter . Logger ( " " ) , } }

// NewWhisper create instance of Whisper


func NewWhisperAggregation() *WhisperAggregation {
	return &WhisperAggregation{
		Data: make([]*whisperAggregationItem, 0),
		Default: &whisperAggregationItem{
			name:                 "default",
			pattern:              nil,
			xFilesFactor:         0.5,
			aggregationMethodStr: "average",
			aggregationMethod:    whisper.Average,
		},
	}
}

func NewWhisperAggregation ( ) * WhisperAggregation { return & WhisperAggregation { Data : make ( [ ] * whisperAggregationItem , 0 ) , Default : & whisperAggregationItem { name : " " , pattern : nil , xFilesFactor : 0.5 , aggregationMethodStr : " " , aggregationMethod : whisper . Average , } , } }

// NewWhisperAggregation create instance of WhisperAggregation


func (a *WhisperAggregation) match(metric string) *whisperAggregationItem {
	for _, s := range a.Data {
		if s.pattern.MatchString(metric) {
			return s
		}
	}
	return a.Default
}

func ( a * WhisperAggregation ) match ( metric string ) * whisperAggregationItem { for _ , s := range a . Data { if s . pattern . MatchString ( metric ) { return s } } return a . Default }


func oldPlain(body []byte) ([]*points.Points, error) {
	result := make([]*points.Points, 4)

	reader := bytes.NewBuffer(body)

	for {
		line, err := reader.ReadBytes('\n')

		if err != nil && err != io.EOF {
			return result, err
		}

		if len(line) == 0 {
			break
		}

		if line[len(line)-1] != '\n' {
			return result, errors.New("unfinished line in file")
		}

		p, err := points.ParseText(string(line))

		if err != nil {
			return result, err
		}

		result = append(result, p)
	}

	return result, nil
}

func oldPlain ( body [ ] byte ) ( [ ] * points . Points , error ) { result := make ( [ ] * points . Points , 4 ) reader := bytes . NewBuffer ( body ) for { line , err := reader . ReadBytes ( '\n' ) if err != nil && err != io . EOF { return result , err } if len ( line ) == 0 { break } if line [ len ( line ) - 1 ] != '\n' { return result , errors . New ( " " ) } p , err := points . ParseText ( string ( line ) ) if err != nil { return result , err } result = append ( result , p ) } return result , nil }


func (client *Client) UpdateIntegrationPD(pdIntegration *IntegrationPDRequest) error {
	return client.doJsonRequest("PUT", "/v1/integration/pagerduty", pdIntegration, nil)
}

func ( client * Client ) UpdateIntegrationPD ( pdIntegration * IntegrationPDRequest ) error { return client . doJsonRequest ( " " , " " , pdIntegration , nil ) }

// UpdateIntegrationPD updates the PagerDuty Integration.
// This will replace the existing values with the new values.

UpdateIntegrationPD updates the PagerDuty Integration . This will replace the existing values with the new values .


func (client *Client) GetIntegrationPD() (*integrationPD, error) {
	var out integrationPD
	if err := client.doJsonRequest("GET", "/v1/integration/pagerduty", nil, &out); err != nil {
		return nil, err
	}

	return &out, nil
}

func ( client * Client ) GetIntegrationPD ( ) ( * integrationPD , error ) { var out integrationPD if err := client . doJsonRequest ( " " , " " , nil , & out ) ; err != nil { return nil , err } return & out , nil }

// GetIntegrationPD gets all the PagerDuty Integrations from the system.

GetIntegrationPD gets all the PagerDuty Integrations from the system .


func (client *Client) CreateIntegrationSlack(slackIntegration *IntegrationSlackRequest) error {
	return client.doJsonRequest("POST", "/v1/integration/slack", slackIntegration, nil)
}

func ( client * Client ) CreateIntegrationSlack ( slackIntegration * IntegrationSlackRequest ) error { return client . doJsonRequest ( " " , " " , slackIntegration , nil ) }

// CreateIntegrationSlack creates new Slack Integrations.
// Use this if you want to setup the integration for the first time
// or to add more channels.

CreateIntegrationSlack creates new Slack Integrations . Use this if you want to setup the integration for the first time or to add more channels .


func (client *Client) UpdateIntegrationSlack(slackIntegration *IntegrationSlackRequest) error {
	return client.doJsonRequest("PUT", "/v1/integration/slack", slackIntegration, nil)
}

func ( client * Client ) UpdateIntegrationSlack ( slackIntegration * IntegrationSlackRequest ) error { return client . doJsonRequest ( " " , " " , slackIntegration , nil ) }

// UpdateIntegrationSlack updates the Slack Integration.
// This will replace the existing values with the new values.

UpdateIntegrationSlack updates the Slack Integration . This will replace the existing values with the new values .


func (client *Client) GetIntegrationSlack() (*IntegrationSlackRequest, error) {
	var out IntegrationSlackRequest
	if err := client.doJsonRequest("GET", "/v1/integration/slack", nil, &out); err != nil {
		return nil, err
	}

	return &out, nil
}

func ( client * Client ) GetIntegrationSlack ( ) ( * IntegrationSlackRequest , error ) { var out IntegrationSlackRequest if err := client . doJsonRequest ( " " , " " , nil , & out ) ; err != nil { return nil , err } return & out , nil }

// GetIntegrationSlack gets all the Slack Integrations from the system.

GetIntegrationSlack gets all the Slack Integrations from the system .


func (client *Client) CreateIntegrationAWS(awsAccount *IntegrationAWSAccount) (*IntegrationAWSAccountCreateResponse, error) {
	var out IntegrationAWSAccountCreateResponse
	if err := client.doJsonRequest("POST", "/v1/integration/aws", awsAccount, &out); err != nil {
		return nil, err
	}

	return &out, nil
}

func ( client * Client ) CreateIntegrationAWS ( awsAccount * IntegrationAWSAccount ) ( * IntegrationAWSAccountCreateResponse , error ) { var out IntegrationAWSAccountCreateResponse if err := client . doJsonRequest ( " " , " " , awsAccount , & out ) ; err != nil { return nil , err } return & out , nil }

// CreateIntegrationAWS adds a new AWS Account in the AWS Integrations.
// Use this if you want to setup the integration for the first time
// or to add more accounts.

CreateIntegrationAWS adds a new AWS Account in the AWS Integrations . Use this if you want to setup the integration for the first time or to add more accounts .


func (client *Client) GetIntegrationAWS() (*[]IntegrationAWSAccount, error) {
	var response IntegrationAWSAccountGetResponse
	if err := client.doJsonRequest("GET", "/v1/integration/aws", nil, &response); err != nil {
		return nil, err
	}

	return &response.Accounts, nil
}

func ( client * Client ) GetIntegrationAWS ( ) ( * [ ] IntegrationAWSAccount , error ) { var response IntegrationAWSAccountGetResponse if err := client . doJsonRequest ( " " , " " , nil , & response ) ; err != nil { return nil , err } return & response . Accounts , nil }

// GetIntegrationAWS gets all the AWS Accounts in the AWS Integrations from Datadog.

GetIntegrationAWS gets all the AWS Accounts in the AWS Integrations from Datadog .


func (client *Client) DeleteIntegrationAWS(awsAccount *IntegrationAWSAccountDeleteRequest) error {
	return client.doJsonRequest("DELETE", "/v1/integration/aws", awsAccount, nil)
}

func ( client * Client ) DeleteIntegrationAWS ( awsAccount * IntegrationAWSAccountDeleteRequest ) error { return client . doJsonRequest ( " " , " " , awsAccount , nil ) }

// DeleteIntegrationAWS removes a specific AWS Account from the AWS Integration.

DeleteIntegrationAWS removes a specific AWS Account from the AWS Integration .


func (client *Client) ListIntegrationGCP() ([]*IntegrationGCP, error) {
	var list []*IntegrationGCP
	if err := client.doJsonRequest("GET", "/v1/integration/gcp", nil, &list); err != nil {
		return nil, err
	}
	return list, nil
}

func ( client * Client ) ListIntegrationGCP ( ) ( [ ] * IntegrationGCP , error ) { var list [ ] * IntegrationGCP if err := client . doJsonRequest ( " " , " " , nil , & list ) ; err != nil { return nil , err } return list , nil }

// ListIntegrationGCP gets all Google Cloud Platform Integrations.

ListIntegrationGCP gets all Google Cloud Platform Integrations .


func (client *Client) CreateIntegrationGCP(cir *IntegrationGCPCreateRequest) error {
	return client.doJsonRequest("POST", "/v1/integration/gcp", cir, nil)
}

func ( client * Client ) CreateIntegrationGCP ( cir * IntegrationGCPCreateRequest ) error { return client . doJsonRequest ( " " , " " , cir , nil ) }

// CreateIntegrationGCP creates a new Google Cloud Platform Integration.

CreateIntegrationGCP creates a new Google Cloud Platform Integration .


func (client *Client) UpdateIntegrationGCP(cir *IntegrationGCPUpdateRequest) error {
	return client.doJsonRequest("POST", "/v1/integration/gcp/host_filters", cir, nil)
}

func ( client * Client ) UpdateIntegrationGCP ( cir * IntegrationGCPUpdateRequest ) error { return client . doJsonRequest ( " " , " " , cir , nil ) }

// UpdateIntegrationGCP updates a Google Cloud Platform Integration.

UpdateIntegrationGCP updates a Google Cloud Platform Integration .


func (client *Client) DeleteIntegrationGCP(cir *IntegrationGCPDeleteRequest) error {
	return client.doJsonRequest("DELETE", "/v1/integration/gcp", cir, nil)
}

func ( client * Client ) DeleteIntegrationGCP ( cir * IntegrationGCPDeleteRequest ) error { return client . doJsonRequest ( " " , " " , cir , nil ) }

// DeleteIntegrationGCP deletes a Google Cloud Platform Integration.

DeleteIntegrationGCP deletes a Google Cloud Platform Integration .


func (client *Client) GetDashboardList(id int) (*DashboardList, error) {
	var out DashboardList
	if err := client.doJsonRequest("GET", fmt.Sprintf("/v1/dashboard/lists/manual/%d", id), nil, &out); err != nil {
		return nil, err
	}
	return &out, nil
}

func ( client * Client ) GetDashboardList ( id int ) ( * DashboardList , error ) { var out DashboardList if err := client . doJsonRequest ( " " , fmt . Sprintf ( " " , id ) , nil , & out ) ; err != nil { return nil , err } return & out , nil }

// GetDashboardList returns a single dashboard list created on this account.

GetDashboardList returns a single dashboard list created on this account .


func (client *Client) GetDashboardLists() ([]DashboardList, error) {
	var out reqGetDashboardLists
	if err := client.doJsonRequest("GET", "/v1/dashboard/lists/manual", nil, &out); err != nil {
		return nil, err
	}
	return out.DashboardLists, nil
}

func ( client * Client ) GetDashboardLists ( ) ( [ ] DashboardList , error ) { var out reqGetDashboardLists if err := client . doJsonRequest ( " " , " " , nil , & out ) ; err != nil { return nil , err } return out . DashboardLists , nil }

// GetDashboardLists returns a list of all dashboard lists created on this account.

GetDashboardLists returns a list of all dashboard lists created on this account .


func (client *Client) CreateDashboardList(list *DashboardList) (*DashboardList, error) {
	var out DashboardList
	if err := client.doJsonRequest("POST", "/v1/dashboard/lists/manual", list, &out); err != nil {
		return nil, err
	}
	return &out, nil
}

func ( client * Client ) CreateDashboardList ( list * DashboardList ) ( * DashboardList , error ) { var out DashboardList if err := client . doJsonRequest ( " " , " " , list , & out ) ; err != nil { return nil , err } return & out , nil }

// CreateDashboardList returns a single dashboard list created on this account.

CreateDashboardList returns a single dashboard list created on this account .


func (client *Client) UpdateDashboardList(list *DashboardList) error {
	req := reqUpdateDashboardList{list.GetName()}
	return client.doJsonRequest("PUT", fmt.Sprintf("/v1/dashboard/lists/manual/%d", *list.Id), req, nil)
}

func ( client * Client ) UpdateDashboardList ( list * DashboardList ) error { req := reqUpdateDashboardList { list . GetName ( ) } return client . doJsonRequest ( " " , fmt . Sprintf ( " " , * list . Id ) , req , nil ) }

// UpdateDashboardList returns a single dashboard list created on this account.

UpdateDashboardList returns a single dashboard list created on this account .


func (client *Client) GetDashboardListItems(id int) ([]DashboardListItem, error) {
	var out reqDashboardListItems
	if err := client.doJsonRequest("GET", fmt.Sprintf("/v1/dashboard/lists/manual/%d/dashboards", id), nil, &out); err != nil {
		return nil, err
	}
	return out.Dashboards, nil
}

func ( client * Client ) GetDashboardListItems ( id int ) ( [ ] DashboardListItem , error ) { var out reqDashboardListItems if err := client . doJsonRequest ( " " , fmt . Sprintf ( " " , id ) , nil , & out ) ; err != nil { return nil , err } return out . Dashboards , nil }

// GetDashboardListItems fetches the dashboard list's dashboard definitions.

GetDashboardListItems fetches the dashboard list s dashboard definitions .


func (client *Client) Snapshot(query string, start, end time.Time, eventQuery string) (string, error) {
	options := map[string]string{"metric_query": query, "event_query": eventQuery}

	return client.SnapshotGeneric(options, start, end)
}

func ( client * Client ) Snapshot ( query string , start , end time . Time , eventQuery string ) ( string , error ) { options := map [ string ] string { " " : query , " " : eventQuery } return client . SnapshotGeneric ( options , start , end ) }

// Snapshot creates an image from a graph and returns the URL of the image.

Snapshot creates an image from a graph and returns the URL of the image .


func (client *Client) SearchHosts(search string) ([]string, error) {
	var out reqSearch
	if err := client.doJsonRequest("GET", "/v1/search?q=hosts:"+search, nil, &out); err != nil {
		return nil, err
	}
	return out.Results.Hosts, nil
}

func ( client * Client ) SearchHosts ( search string ) ( [ ] string , error ) { var out reqSearch if err := client . doJsonRequest ( " " , " " + search , nil , & out ) ; err != nil { return nil , err } return out . Results . Hosts , nil }

// SearchHosts searches through the hosts facet, returning matching hostnames.

SearchHosts searches through the hosts facet returning matching hostnames .


func (client *Client) SearchMetrics(search string) ([]string, error) {
	var out reqSearch
	if err := client.doJsonRequest("GET", "/v1/search?q=metrics:"+search, nil, &out); err != nil {
		return nil, err
	}
	return out.Results.Metrics, nil
}

func ( client * Client ) SearchMetrics ( search string ) ( [ ] string , error ) { var out reqSearch if err := client . doJsonRequest ( " " , " " + search , nil , & out ) ; err != nil { return nil , err } return out . Results . Metrics , nil }

// SearchMetrics searches through the metrics facet, returning matching ones.

SearchMetrics searches through the metrics facet returning matching ones .


func (client *Client) CreateAlert(alert *Alert) (*Alert, error) {
	var out Alert
	if err := client.doJsonRequest("POST", "/v1/alert", alert, &out); err != nil {
		return nil, err
	}
	return &out, nil
}

func ( client * Client ) CreateAlert ( alert * Alert ) ( * Alert , error ) { var out Alert if err := client . doJsonRequest ( " " , " " , alert , & out ) ; err != nil { return nil , err } return & out , nil }

// CreateAlert adds a new alert to the system. This returns a pointer to an
// Alert so you can pass that to UpdateAlert later if needed.

CreateAlert adds a new alert to the system . This returns a pointer to an Alert so you can pass that to UpdateAlert later if needed .


func (client *Client) UpdateAlert(alert *Alert) error {
	return client.doJsonRequest("PUT", fmt.Sprintf("/v1/alert/%d", alert.Id),
		alert, nil)
}

func ( client * Client ) UpdateAlert ( alert * Alert ) error { return client . doJsonRequest ( " " , fmt . Sprintf ( " " , alert . Id ) , alert , nil ) }

// UpdateAlert takes an alert that was previously retrieved through some method
// and sends it back to the server.

UpdateAlert takes an alert that was previously retrieved through some method and sends it back to the server .


func (client *Client) GetAlert(id int) (*Alert, error) {
	var out Alert
	if err := client.doJsonRequest("GET", fmt.Sprintf("/v1/alert/%d", id), nil, &out); err != nil {
		return nil, err
	}
	return &out, nil
}

func ( client * Client ) GetAlert ( id int ) ( * Alert , error ) { var out Alert if err := client . doJsonRequest ( " " , fmt . Sprintf ( " " , id ) , nil , & out ) ; err != nil { return nil , err } return & out , nil }

// GetAlert retrieves an alert by identifier.

GetAlert retrieves an alert by identifier .


func (client *Client) GetAlerts() ([]Alert, error) {
	var out reqAlerts
	if err := client.doJsonRequest("GET", "/v1/alert", nil, &out); err != nil {
		return nil, err
	}
	return out.Alerts, nil
}

func ( client * Client ) GetAlerts ( ) ( [ ] Alert , error ) { var out reqAlerts if err := client . doJsonRequest ( " " , " " , nil , & out ) ; err != nil { return nil , err } return out . Alerts , nil }

// GetAlerts returns a slice of all alerts.

GetAlerts returns a slice of all alerts .


func (client *Client) CreateComment(handle, message string) (*Comment, error) {
	var out reqComment
	comment := Comment{Message: String(message)}
	if len(handle) > 0 {
		comment.Handle = String(handle)
	}
	if err := client.doJsonRequest("POST", "/v1/comments", &comment, &out); err != nil {
		return nil, err
	}
	return out.Comment, nil
}

func ( client * Client ) CreateComment ( handle , message string ) ( * Comment , error ) { var out reqComment comment := Comment { Message : String ( message ) } if len ( handle ) > 0 { comment . Handle = String ( handle ) } if err := client . doJsonRequest ( " " , " " , & comment , & out ) ; err != nil { return nil , err } return out . Comment , nil }

// CreateComment adds a new comment to the system.

CreateComment adds a new comment to the system .


func (client *Client) CreateRelatedComment(handle, message string,
	relid int) (*Comment, error) {
	var out reqComment
	comment := Comment{Message: String(message), RelatedId: Int(relid)}
	if len(handle) > 0 {
		comment.Handle = String(handle)
	}
	if err := client.doJsonRequest("POST", "/v1/comments", &comment, &out); err != nil {
		return nil, err
	}
	return out.Comment, nil
}

func ( client * Client ) CreateRelatedComment ( handle , message string , relid int ) ( * Comment , error ) { var out reqComment comment := Comment { Message : String ( message ) , RelatedId : Int ( relid ) } if len ( handle ) > 0 { comment . Handle = String ( handle ) } if err := client . doJsonRequest ( " " , " " , & comment , & out ) ; err != nil { return nil , err } return out . Comment , nil }

// CreateRelatedComment adds a new comment, but lets you specify the related
// identifier for the comment.

CreateRelatedComment adds a new comment but lets you specify the related identifier for the comment .


func (client *Client) EditComment(id int, handle, message string) error {
	comment := Comment{Message: String(message)}
	if len(handle) > 0 {
		comment.Handle = String(handle)
	}
	return client.doJsonRequest("PUT", fmt.Sprintf("/v1/comments/%d", id),
		&comment, nil)
}

func ( client * Client ) EditComment ( id int , handle , message string ) error { comment := Comment { Message : String ( message ) } if len ( handle ) > 0 { comment . Handle = String ( handle ) } return client . doJsonRequest ( " " , fmt . Sprintf ( " " , id ) , & comment , nil ) }

// EditComment changes the message and possibly handle of a particular comment.

EditComment changes the message and possibly handle of a particular comment .


func (client *Client) CreateMonitor(monitor *Monitor) (*Monitor, error) {
	var out Monitor
	// TODO: is this more pretty of frowned upon?
	if err := client.doJsonRequest("POST", "/v1/monitor", monitor, &out); err != nil {
		return nil, err
	}
	return &out, nil
}

// CreateMonitor adds a new monitor to the system. This returns a pointer to a
// monitor so you can pass that to UpdateMonitor later if needed

CreateMonitor adds a new monitor to the system . This returns a pointer to a monitor so you can pass that to UpdateMonitor later if needed


func (client *Client) UpdateMonitor(monitor *Monitor) error {
	return client.doJsonRequest("PUT", fmt.Sprintf("/v1/monitor/%d", *monitor.Id),
		monitor, nil)
}

func ( client * Client ) UpdateMonitor ( monitor * Monitor ) error { return client . doJsonRequest ( " " , fmt . Sprintf ( " " , * monitor . Id ) , monitor , nil ) }

// UpdateMonitor takes a monitor that was previously retrieved through some method
// and sends it back to the server

UpdateMonitor takes a monitor that was previously retrieved through some method and sends it back to the server


func (client *Client) GetMonitor(id int) (*Monitor, error) {
	var out Monitor
	if err := client.doJsonRequest("GET", fmt.Sprintf("/v1/monitor/%d", id), nil, &out); err != nil {
		return nil, err
	}
	return &out, nil
}

func ( client * Client ) GetMonitor ( id int ) ( * Monitor , error ) { var out Monitor if err := client . doJsonRequest ( " " , fmt . Sprintf ( " " , id ) , nil , & out ) ; err != nil { return nil , err } return & out , nil }

// GetMonitor retrieves a monitor by identifier


func (self *Client) GetMonitorsByName(name string) ([]Monitor, error) {
	var out reqMonitors
	query, err := url.ParseQuery(fmt.Sprintf("name=%v", name))
	if err != nil {
		return nil, err
	}

	err = self.doJsonRequest("GET", fmt.Sprintf("/v1/monitor?%v", query.Encode()), nil, &out.Monitors)
	if err != nil {
		return nil, err
	}
	return out.Monitors, nil
}

func ( self * Client ) GetMonitorsByName ( name string ) ( [ ] Monitor , error ) { var out reqMonitors query , err := url . ParseQuery ( fmt . Sprintf ( " " , name ) ) if err != nil { return nil , err } err = self . doJsonRequest ( " " , fmt . Sprintf ( " " , query . Encode ( ) ) , nil , & out . Monitors ) if err != nil { return nil , err } return out . Monitors , nil }

// GetMonitorsByName retrieves monitors by name


func (self *Client) GetMonitorsByTags(tags []string) ([]Monitor, error) {
	var out reqMonitors
	query, err := url.ParseQuery(fmt.Sprintf("monitor_tags=%v", strings.Join(tags, ",")))
	if err != nil {
		return nil, err
	}

	err = self.doJsonRequest("GET", fmt.Sprintf("/v1/monitor?%v", query.Encode()), nil, &out.Monitors)
	if err != nil {
		return nil, err
	}
	return out.Monitors, nil
}

func ( self * Client ) GetMonitorsByTags ( tags [ ] string ) ( [ ] Monitor , error ) { var out reqMonitors query , err := url . ParseQuery ( fmt . Sprintf ( " " , strings . Join ( tags , " " ) ) ) if err != nil { return nil , err } err = self . doJsonRequest ( " " , fmt . Sprintf ( " " , query . Encode ( ) ) , nil , & out . Monitors ) if err != nil { return nil , err } return out . Monitors , nil }

// GetMonitorsByTags retrieves monitors by a slice of tags


func (client *Client) GetMonitors() ([]Monitor, error) {
	var out reqMonitors
	if err := client.doJsonRequest("GET", "/v1/monitor", nil, &out.Monitors); err != nil {
		return nil, err
	}
	return out.Monitors, nil
}

func ( client * Client ) GetMonitors ( ) ( [ ] Monitor , error ) { var out reqMonitors if err := client . doJsonRequest ( " " , " " , nil , & out . Monitors ) ; err != nil { return nil , err } return out . Monitors , nil }

// GetMonitors returns a slice of all monitors


func (client *Client) GetSyntheticsLocations() ([]SyntheticsLocation, error) {
	var out struct {
		Locations []SyntheticsLocation `json:"locations,omitempty"`
	}
	if err := client.doJsonRequest("GET", "/v1/synthetics/locations", nil, &out); err != nil {
		return nil, err
	}
	return out.Locations, nil
}

func ( client * Client ) GetSyntheticsLocations ( ) ( [ ] SyntheticsLocation , error ) { var out struct { Locations [ ] SyntheticsLocation `json:"locations,omitempty"` } if err := client . doJsonRequest ( " " , " " , nil , & out ) ; err != nil { return nil , err } return out . Locations , nil }

// GetSyntheticsLocations get all test locations


func GetBool(v *bool) (bool, bool) {
	if v != nil {
		return *v, true
	}

	return false, false
}

func GetBool ( v * bool ) ( bool , bool ) { if v != nil { return * v , true } return false , false }

// GetBool is a helper routine that returns a boolean representing
// if a value was set, and if so, dereferences the pointer to it.

GetBool is a helper routine that returns a boolean representing if a value was set and if so dereferences the pointer to it .


func GetIntOk(v *int) (int, bool) {
	if v != nil {
		return *v, true
	}

	return 0, false
}

func GetIntOk ( v * int ) ( int , bool ) { if v != nil { return * v , true } return 0 , false }

// GetIntOk is a helper routine that returns a boolean representing
// if a value was set, and if so, dereferences the pointer to it.

GetIntOk is a helper routine that returns a boolean representing if a value was set and if so dereferences the pointer to it .


func GetStringOk(v *string) (string, bool) {
	if v != nil {
		return *v, true
	}

	return "", false
}

func GetStringOk ( v * string ) ( string , bool ) { if v != nil { return * v , true } return " " , false }

// GetStringOk is a helper routine that returns a boolean representing
// if a value was set, and if so, dereferences the pointer to it.

GetStringOk is a helper routine that returns a boolean representing if a value was set and if so dereferences the pointer to it .


func GetJsonNumberOk(v *json.Number) (json.Number, bool) {
	if v != nil {
		return *v, true
	}

	return "", false
}

func GetJsonNumberOk ( v * json . Number ) ( json . Number , bool ) { if v != nil { return * v , true } return " " , false }

// GetJsonNumberOk is a helper routine that returns a boolean representing
// if a value was set, and if so, dereferences the pointer to it.

GetJsonNumberOk is a helper routine that returns a boolean representing if a value was set and if so dereferences the pointer to it .


func GetPrecision(v *PrecisionT) (PrecisionT, bool) {
	if v != nil {
		return *v, true
	}

	return PrecisionT(""), false
}

func GetPrecision ( v * PrecisionT ) ( PrecisionT , bool ) { if v != nil { return * v , true } return PrecisionT ( " " ) , false }

// GetPrecision is a helper routine that returns a boolean representing
// if a value was set, and if so, dereferences the pointer to it.

GetPrecision is a helper routine that returns a boolean representing if a value was set and if so dereferences the pointer to it .