@ -0,0 +1,15 @@
|
|||||||
|
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||||
|
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/tj/go-debug"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "ff4a55a20a86994118644bbddc6a216da193cc13"
|
||||||
|
version = "v2.0.0"
|
||||||
|
|
||||||
|
[solve-meta]
|
||||||
|
analyzer-name = "dep"
|
||||||
|
analyzer-version = 1
|
||||||
|
inputs-digest = "6a05cef6e16f81ece71d6125d24af0bceb1d65db5c902c7b46eeb6d2a46826d3"
|
||||||
|
solver-name = "gps-cdcl"
|
||||||
|
solver-version = 1
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
|
||||||
|
# Gopkg.toml example
|
||||||
|
#
|
||||||
|
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
|
||||||
|
# for detailed Gopkg.toml documentation.
|
||||||
|
#
|
||||||
|
# required = ["github.com/user/thing/cmd/thing"]
|
||||||
|
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||||
|
#
|
||||||
|
# [[constraint]]
|
||||||
|
# name = "github.com/user/project"
|
||||||
|
# version = "1.0.0"
|
||||||
|
#
|
||||||
|
# [[constraint]]
|
||||||
|
# name = "github.com/user/project2"
|
||||||
|
# branch = "dev"
|
||||||
|
# source = "github.com/myfork/project2"
|
||||||
|
#
|
||||||
|
# [[override]]
|
||||||
|
# name = "github.com/x/y"
|
||||||
|
# version = "2.4.0"
|
||||||
|
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/tj/go-debug"
|
||||||
|
version = "2.0.0"
|
||||||
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 186 KiB After Width: | Height: | Size: 186 KiB |
|
Before Width: | Height: | Size: 198 KiB After Width: | Height: | Size: 198 KiB |
|
Before Width: | Height: | Size: 187 KiB After Width: | Height: | Size: 187 KiB |
|
Before Width: | Height: | Size: 199 KiB After Width: | Height: | Size: 199 KiB |
|
Before Width: | Height: | Size: 187 KiB After Width: | Height: | Size: 187 KiB |
|
Before Width: | Height: | Size: 200 KiB After Width: | Height: | Size: 200 KiB |
|
Before Width: | Height: | Size: 186 KiB After Width: | Height: | Size: 186 KiB |
|
Before Width: | Height: | Size: 199 KiB After Width: | Height: | Size: 199 KiB |
|
Before Width: | Height: | Size: 188 KiB After Width: | Height: | Size: 188 KiB |
|
Before Width: | Height: | Size: 205 KiB After Width: | Height: | Size: 205 KiB |
|
Before Width: | Height: | Size: 189 KiB After Width: | Height: | Size: 189 KiB |
|
Before Width: | Height: | Size: 205 KiB After Width: | Height: | Size: 205 KiB |
|
Before Width: | Height: | Size: 188 KiB After Width: | Height: | Size: 188 KiB |
|
Before Width: | Height: | Size: 204 KiB After Width: | Height: | Size: 204 KiB |
|
Before Width: | Height: | Size: 189 KiB After Width: | Height: | Size: 189 KiB |
|
Before Width: | Height: | Size: 205 KiB After Width: | Height: | Size: 205 KiB |
|
Before Width: | Height: | Size: 153 KiB After Width: | Height: | Size: 153 KiB |
|
Before Width: | Height: | Size: 165 KiB After Width: | Height: | Size: 165 KiB |
|
Before Width: | Height: | Size: 154 KiB After Width: | Height: | Size: 154 KiB |
|
Before Width: | Height: | Size: 166 KiB After Width: | Height: | Size: 166 KiB |
|
Before Width: | Height: | Size: 154 KiB After Width: | Height: | Size: 154 KiB |
|
Before Width: | Height: | Size: 166 KiB After Width: | Height: | Size: 166 KiB |
|
Before Width: | Height: | Size: 154 KiB After Width: | Height: | Size: 154 KiB |
|
Before Width: | Height: | Size: 165 KiB After Width: | Height: | Size: 165 KiB |
|
Before Width: | Height: | Size: 154 KiB After Width: | Height: | Size: 154 KiB |
|
Before Width: | Height: | Size: 174 KiB After Width: | Height: | Size: 174 KiB |
|
Before Width: | Height: | Size: 154 KiB After Width: | Height: | Size: 154 KiB |
|
Before Width: | Height: | Size: 174 KiB After Width: | Height: | Size: 174 KiB |
|
Before Width: | Height: | Size: 153 KiB After Width: | Height: | Size: 153 KiB |
|
Before Width: | Height: | Size: 173 KiB After Width: | Height: | Size: 173 KiB |
|
Before Width: | Height: | Size: 154 KiB After Width: | Height: | Size: 154 KiB |
|
Before Width: | Height: | Size: 174 KiB After Width: | Height: | Size: 174 KiB |
|
Before Width: | Height: | Size: 810 KiB After Width: | Height: | Size: 810 KiB |
|
Before Width: | Height: | Size: 635 KiB After Width: | Height: | Size: 635 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 604 KiB After Width: | Height: | Size: 604 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 111 KiB After Width: | Height: | Size: 111 KiB |
|
Before Width: | Height: | Size: 142 KiB After Width: | Height: | Size: 142 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 64 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 134 KiB After Width: | Height: | Size: 134 KiB |
|
Before Width: | Height: | Size: 117 KiB After Width: | Height: | Size: 117 KiB |
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 78 KiB |
|
Before Width: | Height: | Size: 2.9 MiB After Width: | Height: | Size: 2.9 MiB |
|
Before Width: | Height: | Size: 2.0 MiB After Width: | Height: | Size: 2.0 MiB |
@ -0,0 +1,21 @@
|
|||||||
|
|
||||||
|
v2.0.0 / 2014-10-22
|
||||||
|
==================
|
||||||
|
|
||||||
|
* remove live toggling feature. Closes #10
|
||||||
|
|
||||||
|
1.1.1 / 2014-07-07
|
||||||
|
==================
|
||||||
|
|
||||||
|
* fix: dispose socket. Closes #1
|
||||||
|
|
||||||
|
1.1.0 / 2014-06-29
|
||||||
|
==================
|
||||||
|
|
||||||
|
* add unix domain socket live debugging support
|
||||||
|
* add support for enabling/disabling at runtime
|
||||||
|
|
||||||
|
0.1.0 / 2014-05-24
|
||||||
|
==================
|
||||||
|
|
||||||
|
* add global and debug relative deltas
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
test:
|
||||||
|
@go test
|
||||||
|
|
||||||
|
bench:
|
||||||
|
@go test -bench=.
|
||||||
|
|
||||||
|
.PHONY: bench test
|
||||||
@ -0,0 +1,75 @@
|
|||||||
|
|
||||||
|
# go-debug
|
||||||
|
|
||||||
|
Conditional debug logging for Go libraries.
|
||||||
|
|
||||||
|
View the [docs](http://godoc.org/github.com/tj/go-debug).
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```
|
||||||
|
$ go get github.com/tj/go-debug
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import . "github.com/tj/go-debug"
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
var debug = Debug("single")
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
for {
|
||||||
|
debug("sending mail")
|
||||||
|
debug("send email to %s", "tobi@segment.io")
|
||||||
|
debug("send email to %s", "loki@segment.io")
|
||||||
|
debug("send email to %s", "jane@segment.io")
|
||||||
|
time.Sleep(500 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If you run the program with the `DEBUG=*` environment variable you will see:
|
||||||
|
|
||||||
|
```
|
||||||
|
15:58:15.115 34us 33us single - sending mail
|
||||||
|
15:58:15.116 3us 3us single - send email to tobi@segment.io
|
||||||
|
15:58:15.116 1us 1us single - send email to loki@segment.io
|
||||||
|
15:58:15.116 1us 1us single - send email to jane@segment.io
|
||||||
|
15:58:15.620 504ms 504ms single - sending mail
|
||||||
|
15:58:15.620 6us 6us single - send email to tobi@segment.io
|
||||||
|
15:58:15.620 4us 4us single - send email to loki@segment.io
|
||||||
|
15:58:15.620 4us 4us single - send email to jane@segment.io
|
||||||
|
15:58:16.123 503ms 503ms single - sending mail
|
||||||
|
15:58:16.123 7us 7us single - send email to tobi@segment.io
|
||||||
|
15:58:16.123 4us 4us single - send email to loki@segment.io
|
||||||
|
15:58:16.123 4us 4us single - send email to jane@segment.io
|
||||||
|
15:58:16.625 501ms 501ms single - sending mail
|
||||||
|
15:58:16.625 4us 4us single - send email to tobi@segment.io
|
||||||
|
15:58:16.625 4us 4us single - send email to loki@segment.io
|
||||||
|
15:58:16.625 5us 5us single - send email to jane@segment.io
|
||||||
|
```
|
||||||
|
|
||||||
|
A timestamp and two deltas are displayed. The timestamp consists of hour, minute, second and microseconds. The left-most delta is relative to the previous debug call of any name, followed by a delta specific to that debug function. These may be useful to identify timing issues and potential bottlenecks.
|
||||||
|
|
||||||
|
## The DEBUG environment variable
|
||||||
|
|
||||||
|
Executables often support `--verbose` flags for conditional logging, however
|
||||||
|
libraries typically either require altering your code to enable logging,
|
||||||
|
or simply omit logging all together. go-debug allows conditional logging
|
||||||
|
to be enabled via the __DEBUG__ environment variable, where one or more
|
||||||
|
patterns may be specified.
|
||||||
|
|
||||||
|
For example suppose your application has several models and you want
|
||||||
|
to output logs for users only, you might use `DEBUG=models:user`. In contrast
|
||||||
|
if you wanted to see what all database activity was you might use `DEBUG=models:*`,
|
||||||
|
or if you're love being swamped with logs: `DEBUG=*`. You may also specify a list of names delimited by a comma, for example `DEBUG=mongo,redis:*`.
|
||||||
|
|
||||||
|
The name given _should_ be the package name, however you can use whatever you like.
|
||||||
|
|
||||||
|
# License
|
||||||
|
|
||||||
|
MIT
|
||||||
@ -0,0 +1,128 @@
|
|||||||
|
package debug
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"math/rand"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
writer io.Writer = os.Stderr
|
||||||
|
reg *regexp.Regexp
|
||||||
|
m sync.Mutex
|
||||||
|
enabled = false
|
||||||
|
)
|
||||||
|
|
||||||
|
// Debugger function.
|
||||||
|
type DebugFunction func(string, ...interface{})
|
||||||
|
|
||||||
|
// Terminal colors used at random.
|
||||||
|
var colors []string = []string{
|
||||||
|
"31",
|
||||||
|
"32",
|
||||||
|
"33",
|
||||||
|
"34",
|
||||||
|
"35",
|
||||||
|
"36",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize with DEBUG environment variable.
|
||||||
|
func init() {
|
||||||
|
env := os.Getenv("DEBUG")
|
||||||
|
|
||||||
|
if "" != env {
|
||||||
|
Enable(env)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetWriter replaces the default of os.Stderr with `w`.
|
||||||
|
func SetWriter(w io.Writer) {
|
||||||
|
m.Lock()
|
||||||
|
defer m.Unlock()
|
||||||
|
writer = w
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable all pattern matching. This function is thread-safe.
|
||||||
|
func Disable() {
|
||||||
|
m.Lock()
|
||||||
|
defer m.Unlock()
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable the given debug `pattern`. Patterns take a glob-like form,
|
||||||
|
// for example if you wanted to enable everything, just use "*", or
|
||||||
|
// if you had a library named mongodb you could use "mongodb:connection",
|
||||||
|
// or "mongodb:*". Multiple matches can be made with a comma, for
|
||||||
|
// example "mongo*,redis*".
|
||||||
|
//
|
||||||
|
// This function is thread-safe.
|
||||||
|
func Enable(pattern string) {
|
||||||
|
m.Lock()
|
||||||
|
defer m.Unlock()
|
||||||
|
pattern = regexp.QuoteMeta(pattern)
|
||||||
|
pattern = strings.Replace(pattern, "\\*", ".*?", -1)
|
||||||
|
pattern = strings.Replace(pattern, ",", "|", -1)
|
||||||
|
pattern = "^(" + pattern + ")$"
|
||||||
|
reg = regexp.MustCompile(pattern)
|
||||||
|
enabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug creates a debug function for `name` which you call
|
||||||
|
// with printf-style arguments in your application or library.
|
||||||
|
func Debug(name string) DebugFunction {
|
||||||
|
prevGlobal := time.Now()
|
||||||
|
color := colors[rand.Intn(len(colors))]
|
||||||
|
prev := time.Now()
|
||||||
|
|
||||||
|
return func(format string, args ...interface{}) {
|
||||||
|
if !enabled {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reg.MatchString(name) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
d := deltas(prevGlobal, prev, color)
|
||||||
|
fmt.Fprintf(writer, d+" \033["+color+"m"+name+"\033[0m - "+format+"\n", args...)
|
||||||
|
prevGlobal = time.Now()
|
||||||
|
prev = time.Now()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return formatting for deltas.
|
||||||
|
func deltas(prevGlobal, prev time.Time, color string) string {
|
||||||
|
now := time.Now()
|
||||||
|
global := now.Sub(prevGlobal).Nanoseconds()
|
||||||
|
delta := now.Sub(prev).Nanoseconds()
|
||||||
|
ts := now.UTC().Format("15:04:05.000")
|
||||||
|
deltas := fmt.Sprintf("%s %-6s \033["+color+"m%-6s", ts, humanizeNano(global), humanizeNano(delta))
|
||||||
|
return deltas
|
||||||
|
}
|
||||||
|
|
||||||
|
// Humanize nanoseconds to a string.
|
||||||
|
func humanizeNano(n int64) string {
|
||||||
|
var suffix string
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case n > 1e9:
|
||||||
|
n /= 1e9
|
||||||
|
suffix = "s"
|
||||||
|
case n > 1e6:
|
||||||
|
n /= 1e6
|
||||||
|
suffix = "ms"
|
||||||
|
case n > 1e3:
|
||||||
|
n /= 1e3
|
||||||
|
suffix = "us"
|
||||||
|
default:
|
||||||
|
suffix = "ns"
|
||||||
|
}
|
||||||
|
|
||||||
|
return strconv.Itoa(int(n)) + suffix
|
||||||
|
}
|
||||||
@ -0,0 +1,152 @@
|
|||||||
|
package debug
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
import "strings"
|
||||||
|
import "bytes"
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
func assertContains(t *testing.T, str, substr string) {
|
||||||
|
if !strings.Contains(str, substr) {
|
||||||
|
t.Fatalf("expected %q to contain %q", str, substr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertNotContains(t *testing.T, str, substr string) {
|
||||||
|
if strings.Contains(str, substr) {
|
||||||
|
t.Fatalf("expected %q to not contain %q", str, substr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDefault(t *testing.T) {
|
||||||
|
var b []byte
|
||||||
|
buf := bytes.NewBuffer(b)
|
||||||
|
SetWriter(buf)
|
||||||
|
|
||||||
|
debug := Debug("foo")
|
||||||
|
debug("something")
|
||||||
|
debug("here")
|
||||||
|
debug("whoop")
|
||||||
|
|
||||||
|
if buf.Len() != 0 {
|
||||||
|
t.Fatalf("buffer should be empty")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEnable(t *testing.T) {
|
||||||
|
var b []byte
|
||||||
|
buf := bytes.NewBuffer(b)
|
||||||
|
SetWriter(buf)
|
||||||
|
|
||||||
|
Enable("foo")
|
||||||
|
|
||||||
|
debug := Debug("foo")
|
||||||
|
debug("something")
|
||||||
|
debug("here")
|
||||||
|
debug("whoop")
|
||||||
|
|
||||||
|
if buf.Len() == 0 {
|
||||||
|
t.Fatalf("buffer should have output")
|
||||||
|
}
|
||||||
|
|
||||||
|
str := string(buf.Bytes())
|
||||||
|
assertContains(t, str, "something")
|
||||||
|
assertContains(t, str, "here")
|
||||||
|
assertContains(t, str, "whoop")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMultipleOneEnabled(t *testing.T) {
|
||||||
|
var b []byte
|
||||||
|
buf := bytes.NewBuffer(b)
|
||||||
|
SetWriter(buf)
|
||||||
|
|
||||||
|
Enable("foo")
|
||||||
|
|
||||||
|
foo := Debug("foo")
|
||||||
|
foo("foo")
|
||||||
|
|
||||||
|
bar := Debug("bar")
|
||||||
|
bar("bar")
|
||||||
|
|
||||||
|
if buf.Len() == 0 {
|
||||||
|
t.Fatalf("buffer should have output")
|
||||||
|
}
|
||||||
|
|
||||||
|
str := string(buf.Bytes())
|
||||||
|
assertContains(t, str, "foo")
|
||||||
|
assertNotContains(t, str, "bar")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMultipleEnabled(t *testing.T) {
|
||||||
|
var b []byte
|
||||||
|
buf := bytes.NewBuffer(b)
|
||||||
|
SetWriter(buf)
|
||||||
|
|
||||||
|
Enable("foo,bar")
|
||||||
|
|
||||||
|
foo := Debug("foo")
|
||||||
|
foo("foo")
|
||||||
|
|
||||||
|
bar := Debug("bar")
|
||||||
|
bar("bar")
|
||||||
|
|
||||||
|
if buf.Len() == 0 {
|
||||||
|
t.Fatalf("buffer should have output")
|
||||||
|
}
|
||||||
|
|
||||||
|
str := string(buf.Bytes())
|
||||||
|
assertContains(t, str, "foo")
|
||||||
|
assertContains(t, str, "bar")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEnableDisable(t *testing.T) {
|
||||||
|
var b []byte
|
||||||
|
buf := bytes.NewBuffer(b)
|
||||||
|
SetWriter(buf)
|
||||||
|
|
||||||
|
Enable("foo,bar")
|
||||||
|
Disable()
|
||||||
|
|
||||||
|
foo := Debug("foo")
|
||||||
|
foo("foo")
|
||||||
|
|
||||||
|
bar := Debug("bar")
|
||||||
|
bar("bar")
|
||||||
|
|
||||||
|
if buf.Len() != 0 {
|
||||||
|
t.Fatalf("buffer should not have output")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleEnable() {
|
||||||
|
Enable("mongo:connection")
|
||||||
|
Enable("mongo:*")
|
||||||
|
Enable("foo,bar,baz")
|
||||||
|
Enable("*")
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleDebug() {
|
||||||
|
var debug = Debug("single")
|
||||||
|
|
||||||
|
for {
|
||||||
|
debug("sending mail")
|
||||||
|
debug("send email to %s", "tobi@segment.io")
|
||||||
|
debug("send email to %s", "loki@segment.io")
|
||||||
|
debug("send email to %s", "jane@segment.io")
|
||||||
|
time.Sleep(500 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkDisabled(b *testing.B) {
|
||||||
|
debug := Debug("something")
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
debug("stuff")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkNonMatch(b *testing.B) {
|
||||||
|
debug := Debug("something")
|
||||||
|
Enable("nonmatch")
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
debug("stuff")
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import . "github.com/visionmedia/go-debug"
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
var a = Debug("multiple:a")
|
||||||
|
var b = Debug("multiple:b")
|
||||||
|
var c = Debug("multiple:c")
|
||||||
|
|
||||||
|
func work(debug DebugFunction, delay time.Duration) {
|
||||||
|
for {
|
||||||
|
debug("doing stuff")
|
||||||
|
time.Sleep(delay)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
q := make(chan bool)
|
||||||
|
|
||||||
|
go work(a, 1000*time.Millisecond)
|
||||||
|
go work(b, 250*time.Millisecond)
|
||||||
|
go work(c, 100*time.Millisecond)
|
||||||
|
|
||||||
|
<-q
|
||||||
|
}
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import . "github.com/visionmedia/go-debug"
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
var debug = Debug("single")
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
for {
|
||||||
|
debug("sending mail")
|
||||||
|
debug("send email to %s", "tobi@segment.io")
|
||||||
|
debug("send email to %s", "loki@segment.io")
|
||||||
|
debug("send email to %s", "jane@segment.io")
|
||||||
|
time.Sleep(500 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||