Merge pull request #143 from henrikhodne/do-not-quote-9

Text formatter: Do not quote 9
diff --git a/README.md b/README.md
index 6227b3f..e755e7c 100644
--- a/README.md
+++ b/README.md
@@ -2,9 +2,10 @@
 
 Logrus is a structured logger for Go (golang), completely API compatible with
 the standard library logger. [Godoc][godoc]. **Please note the Logrus API is not
-yet stable (pre 1.0), the core API is unlikely to change much but please version
-control your Logrus to make sure you aren't fetching latest `master` on every
-build.**
+yet stable (pre 1.0). Logrus itself is completely stable and has been used in
+many large deployments. The core API is unlikely to change much but please
+version control your Logrus to make sure you aren't fetching latest `master` on
+every build.**
 
 Nicely color-coded in development (when a TTY is attached, otherwise just
 plain text):
@@ -241,6 +242,9 @@
 * [`github.com/johntdyer/slackrus`](https://github.com/johntdyer/slackrus)
   Hook for Slack chat.
 
+* [`github.com/wercker/journalhook`](https://github.com/wercker/journalhook).
+  Hook for logging to `systemd-journald`.
+
 #### Level logging
 
 Logrus has six logging levels: Debug, Info, Warning, Error, Fatal and Panic.
@@ -347,7 +351,7 @@
 
 #### Logger as an `io.Writer`
 
-Logrus can be transormed into an `io.Writer`. That writer is the end of an `io.Pipe` and it is your responsability to close it.
+Logrus can be transormed into an `io.Writer`. That writer is the end of an `io.Pipe` and it is your responsibility to close it.
 
 ```go
 w := logger.Writer()
@@ -366,7 +370,7 @@
 #### Rotation
 
 Log rotation is not provided with Logrus. Log rotation should be done by an
-external program (like `logrotated(8)`) that can compress and delete old log
+external program (like `logrotate(8)`) that can compress and delete old log
 entries. It should not be a feature of the application-level logger.
 
 
diff --git a/exported.go b/exported.go
index fd092fc..a67e1b8 100644
--- a/exported.go
+++ b/exported.go
@@ -36,6 +36,8 @@
 
 // GetLevel returns the standard logger level.
 func GetLevel() Level {
+	std.mu.Lock()
+	defer std.mu.Unlock()
 	return std.Level
 }
 
diff --git a/hooks/sentry/README.md b/hooks/sentry/README.md
index a409f3b..19e58bb 100644
--- a/hooks/sentry/README.md
+++ b/hooks/sentry/README.md
@@ -57,5 +57,5 @@
 
 ```go
 hook, _ := logrus_sentry.NewSentryHook(...)
-hook.Timeout = 20*time.Seconds
+hook.Timeout = 20*time.Second
 ```
diff --git a/logrus_test.go b/logrus_test.go
index 7f52c6f..d85dba4 100644
--- a/logrus_test.go
+++ b/logrus_test.go
@@ -5,6 +5,7 @@
 	"encoding/json"
 	"strconv"
 	"strings"
+	"sync"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
@@ -281,3 +282,20 @@
 	l, err = ParseLevel("invalid")
 	assert.Equal(t, "not a valid logrus Level: \"invalid\"", err.Error())
 }
+
+func TestGetSetLevelRace(t *testing.T) {
+	wg := sync.WaitGroup{}
+	for i := 0; i < 100; i++ {
+		wg.Add(1)
+		go func(i int) {
+			defer wg.Done()
+			if i%2 == 0 {
+				SetLevel(InfoLevel)
+			} else {
+				GetLevel()
+			}
+		}(i)
+
+	}
+	wg.Wait()
+}
diff --git a/text_formatter.go b/text_formatter.go
index a147192..e44f1e1 100644
--- a/text_formatter.go
+++ b/text_formatter.go
@@ -34,16 +34,23 @@
 
 type TextFormatter struct {
 	// Set to true to bypass checking for a TTY before outputting colors.
-	ForceColors   bool
+	ForceColors bool
+
+	// Force disabling colors.
 	DisableColors bool
-	// Set to true to disable timestamp logging (useful when the output
-	// is redirected to a logging system already adding a timestamp)
+
+	// Disable timestamp logging. useful when output is redirected to logging
+	// system that already adds timestamps.
 	DisableTimestamp bool
+
+	// Enable logging the full timestamp when a TTY is attached instead of just
+	// the time passed since beginning of execution.
+	FullTimestamp bool
 }
 
 func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
 
-	var keys []string
+	var keys []string = make([]string, 0, len(entry.Data))
 	for k := range entry.Data {
 		keys = append(keys, k)
 	}
@@ -56,7 +63,7 @@
 	isColored := (f.ForceColors || isTerminal) && !f.DisableColors
 
 	if isColored {
-		printColored(b, entry, keys)
+		f.printColored(b, entry, keys)
 	} else {
 		if !f.DisableTimestamp {
 			f.appendKeyValue(b, "time", entry.Time.Format(time.RFC3339))
@@ -72,7 +79,7 @@
 	return b.Bytes(), nil
 }
 
-func printColored(b *bytes.Buffer, entry *Entry, keys []string) {
+func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string) {
 	var levelColor int
 	switch entry.Level {
 	case WarnLevel:
@@ -85,7 +92,11 @@
 
 	levelText := strings.ToUpper(entry.Level.String())[0:4]
 
-	fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message)
+	if !f.FullTimestamp {
+		fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message)
+	} else {
+		fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(time.RFC3339), entry.Message)
+	}
 	for _, k := range keys {
 		v := entry.Data[k]
 		fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=%v", levelColor, k, v)