diff --git a/cmd/cloudflared/hello.go b/cmd/cloudflared/hello.go
index 9f73ade8..b2cd332d 100644
--- a/cmd/cloudflared/hello.go
+++ b/cmd/cloudflared/hello.go
@@ -103,7 +103,7 @@ func hello(c *cli.Context) error {
 }
 
 func startHelloWorldServer(listener net.Listener, shutdownC <-chan struct{}) error {
-	Log.Infof("Starting Hello World server at %s", listener.Addr())
+	logger.Infof("Starting Hello World server at %s", listener.Addr())
 	serverName := defaultServerName
 	if hostname, err := os.Hostname(); err == nil {
 		serverName = hostname
diff --git a/cmd/cloudflared/linux_service.go b/cmd/cloudflared/linux_service.go
index d0b15937..4e859617 100644
--- a/cmd/cloudflared/linux_service.go
+++ b/cmd/cloudflared/linux_service.go
@@ -90,8 +90,8 @@ var sysvTemplate = ServiceTemplate{
 # Short-Description: Argo Tunnel
 # Description:       Argo Tunnel agent
 ### END INIT INFO
-cmd="{{.Path}} --config /etc/cloudflared/config.yml --origincert /etc/cloudflared/cert.pem --pidfile /var/run/$name.pid --autoupdate-freq 24h0m0s"
 name=$(basename $(readlink -f $0))
+cmd="{{.Path}} --config /etc/cloudflared/config.yml --origincert /etc/cloudflared/cert.pem --pidfile /var/run/$name.pid --autoupdate-freq 24h0m0s"
 pid_file="/var/run/$name.pid"
 stdout_log="/var/log/$name.log"
 stderr_log="/var/log/$name.err"
@@ -184,17 +184,17 @@ func installLinuxService(c *cli.Context) error {
 	defaultConfigDir := filepath.Dir(c.String("config"))
 	defaultConfigFile := filepath.Base(c.String("config"))
 	if err = copyCredentials(serviceConfigDir, defaultConfigDir, defaultConfigFile); err != nil {
-		Log.WithError(err).Infof("Failed to copy user configuration. Before running the service, ensure that %s contains two files, %s and %s",
+		logger.WithError(err).Infof("Failed to copy user configuration. Before running the service, ensure that %s contains two files, %s and %s",
 			serviceConfigDir, credentialFile, defaultConfigFiles[0])
 		return err
 	}
 
 	switch {
 	case isSystemd():
-		Log.Infof("Using Systemd")
+		logger.Infof("Using Systemd")
 		return installSystemd(&templateArgs)
 	default:
-		Log.Infof("Using Sysv")
+		logger.Infof("Using Sysv")
 		return installSysv(&templateArgs)
 	}
 }
@@ -203,30 +203,30 @@ func installSystemd(templateArgs *ServiceTemplateArgs) error {
 	for _, serviceTemplate := range systemdTemplates {
 		err := serviceTemplate.Generate(templateArgs)
 		if err != nil {
-			Log.WithError(err).Infof("error generating service template")
+			logger.WithError(err).Infof("error generating service template")
 			return err
 		}
 	}
 	if err := runCommand("systemctl", "enable", "cloudflared.service"); err != nil {
-		Log.WithError(err).Infof("systemctl enable cloudflared.service error")
+		logger.WithError(err).Infof("systemctl enable cloudflared.service error")
 		return err
 	}
 	if err := runCommand("systemctl", "start", "cloudflared-update.timer"); err != nil {
-		Log.WithError(err).Infof("systemctl start cloudflared-update.timer error")
+		logger.WithError(err).Infof("systemctl start cloudflared-update.timer error")
 		return err
 	}
-	Log.Infof("systemctl daemon-reload")
+	logger.Infof("systemctl daemon-reload")
 	return runCommand("systemctl", "daemon-reload")
 }
 
 func installSysv(templateArgs *ServiceTemplateArgs) error {
 	confPath, err := sysvTemplate.ResolvePath()
 	if err != nil {
-		Log.WithError(err).Infof("error resolving system path")
+		logger.WithError(err).Infof("error resolving system path")
 		return err
 	}
 	if err := sysvTemplate.Generate(templateArgs); err != nil {
-		Log.WithError(err).Infof("error generating system template")
+		logger.WithError(err).Infof("error generating system template")
 		return err
 	}
 	for _, i := range [...]string{"2", "3", "4", "5"} {
@@ -245,36 +245,36 @@ func installSysv(templateArgs *ServiceTemplateArgs) error {
 func uninstallLinuxService(c *cli.Context) error {
 	switch {
 	case isSystemd():
-		Log.Infof("Using Systemd")
+		logger.Infof("Using Systemd")
 		return uninstallSystemd()
 	default:
-		Log.Infof("Using Sysv")
+		logger.Infof("Using Sysv")
 		return uninstallSysv()
 	}
 }
 
 func uninstallSystemd() error {
 	if err := runCommand("systemctl", "disable", "cloudflared.service"); err != nil {
-		Log.WithError(err).Infof("systemctl disable cloudflared.service error")
+		logger.WithError(err).Infof("systemctl disable cloudflared.service error")
 		return err
 	}
 	if err := runCommand("systemctl", "stop", "cloudflared-update.timer"); err != nil {
-		Log.WithError(err).Infof("systemctl stop cloudflared-update.timer error")
+		logger.WithError(err).Infof("systemctl stop cloudflared-update.timer error")
 		return err
 	}
 	for _, serviceTemplate := range systemdTemplates {
 		if err := serviceTemplate.Remove(); err != nil {
-			Log.WithError(err).Infof("error removing service template")
+			logger.WithError(err).Infof("error removing service template")
 			return err
 		}
 	}
-	Log.Infof("Successfully uninstall cloudflared service")
+	logger.Infof("Successfully uninstall cloudflared service")
 	return nil
 }
 
 func uninstallSysv() error {
 	if err := sysvTemplate.Remove(); err != nil {
-		Log.WithError(err).Infof("error removing service template")
+		logger.WithError(err).Infof("error removing service template")
 		return err
 	}
 	for _, i := range [...]string{"2", "3", "4", "5"} {
@@ -287,6 +287,6 @@ func uninstallSysv() error {
 			continue
 		}
 	}
-	Log.Infof("Successfully uninstall cloudflared service")
+	logger.Infof("Successfully uninstall cloudflared service")
 	return nil
 }
diff --git a/cmd/cloudflared/login.go b/cmd/cloudflared/login.go
index fa3c675e..1ba234ec 100644
--- a/cmd/cloudflared/login.go
+++ b/cmd/cloudflared/login.go
@@ -136,7 +136,7 @@ func download(certURL, filePath string) bool {
 			return true
 		}
 		if err != nil {
-			Log.WithError(err).Error("Error fetching certificate")
+			logger.WithError(err).Error("Error fetching certificate")
 			return false
 		}
 	}
@@ -179,16 +179,16 @@ func putSuccess(client *http.Client, certURL string) {
 	// indicate success to the relay server
 	req, err := http.NewRequest("PUT", certURL+"/ok", nil)
 	if err != nil {
-		Log.WithError(err).Error("HTTP request error")
+		logger.WithError(err).Error("HTTP request error")
 		return
 	}
 	resp, err := client.Do(req)
 	if err != nil {
-		Log.WithError(err).Error("HTTP error")
+		logger.WithError(err).Error("HTTP error")
 		return
 	}
 	resp.Body.Close()
 	if resp.StatusCode != 200 {
-		Log.Errorf("Unexpected HTTP error code %d", resp.StatusCode)
+		logger.Errorf("Unexpected HTTP error code %d", resp.StatusCode)
 	}
 }
diff --git a/cmd/cloudflared/macos_service.go b/cmd/cloudflared/macos_service.go
index b0ce57b3..37737c57 100644
--- a/cmd/cloudflared/macos_service.go
+++ b/cmd/cloudflared/macos_service.go
@@ -9,7 +9,9 @@ import (
 	"gopkg.in/urfave/cli.v2"
 )
 
-const launchAgentIdentifier = "com.cloudflare.cloudflared"
+const (
+	launchdIdentifier = "com.cloudflare.cloudflared"
+)
 
 func runApp(app *cli.App) {
 	app.Commands = append(app.Commands, &cli.Command{
@@ -32,7 +34,7 @@ func runApp(app *cli.App) {
 }
 
 var launchdTemplate = ServiceTemplate{
-	Path: installPath(launchAgentIdentifier),
+	Path: installPath(),
 	Content: fmt.Sprintf(`
 
 
@@ -46,9 +48,9 @@ var launchdTemplate = ServiceTemplate{
 		RunAtLoad
 		
 		StandardOutPath
-		/tmp/%s.out.log
-    StandardErrorPath
-		/tmp/%s.err.log
+		%s
+		StandardErrorPath
+		%s
 		KeepAlive
 		
 			SuccessfulExit
@@ -57,54 +59,84 @@ var launchdTemplate = ServiceTemplate{
 		ThrottleInterval
 		20
 	
-`, launchAgentIdentifier, launchAgentIdentifier, launchAgentIdentifier),
+`, launchdIdentifier, stdoutPath(), stderrPath()),
 }
 
-func installPath(launchAgentIdentifier string) string {
-	pathPattern := "~/Library/LaunchAgents/%s.plist"
+func isRootUser() bool {
+	return os.Geteuid() == 0
+}
 
+func installPath() string {
 	// User is root, use /Library/LaunchDaemons instead of home directory
-	if os.Geteuid() == 0 {
-		pathPattern = "/Library/LaunchDaemons/%s.plist"
+	if isRootUser() {
+		return fmt.Sprintf("/Library/LaunchDaemons/%s.plist", launchdIdentifier)
 	}
+	return fmt.Sprintf("%s/Library/LaunchAgents/%s.plist", userHomeDir(), launchdIdentifier)
+}
 
-	return fmt.Sprintf(pathPattern, launchAgentIdentifier)
+func stdoutPath() string {
+	if isRootUser() {
+		return fmt.Sprintf("/Library/Logs/%s.out.log", launchdIdentifier)
+	}
+	return fmt.Sprintf("%s/Library/Logs/%s.out.log", userHomeDir(), launchdIdentifier)
+}
+
+func stderrPath() string {
+	if isRootUser() {
+		return fmt.Sprintf("/Library/Logs/%s.err.log", launchdIdentifier)
+	}
+	return fmt.Sprintf("%s/Library/Logs/%s.err.log", userHomeDir(), launchdIdentifier)
 }
 
 func installLaunchd(c *cli.Context) error {
-	Log.Infof("Installing Argo Tunnel as an user launch agent")
+	if isRootUser() {
+		logger.Infof("Installing Argo Tunnel client as a system launch daemon. " +
+		"Argo Tunnel client will run at boot")
+	} else {
+		logger.Infof("Installing Argo Tunnel client as an user launch agent. " +
+		"Note that Argo Tunnel client will only run when the user is logged in. " +
+		"If you want to run Argo Tunnel client at boot, install with root permission. " +
+		"For more information, visit https://developers.cloudflare.com/argo-tunnel/reference/service/")
+	}
 	etPath, err := os.Executable()
 	if err != nil {
-		Log.WithError(err).Infof("error determining executable path")
+		logger.WithError(err).Infof("error determining executable path")
 		return fmt.Errorf("error determining executable path: %v", err)
 	}
 	templateArgs := ServiceTemplateArgs{Path: etPath}
 	err = launchdTemplate.Generate(&templateArgs)
 	if err != nil {
-		Log.WithError(err).Infof("error generating launchd template")
+		logger.WithError(err).Infof("error generating launchd template")
 		return err
 	}
 	plistPath, err := launchdTemplate.ResolvePath()
 	if err != nil {
-		Log.WithError(err).Infof("error resolving launchd template path")
+		logger.WithError(err).Infof("error resolving launchd template path")
 		return err
 	}
-	Log.Infof("Outputs are logged in %s and %s", fmt.Sprintf("/tmp/%s.out.log", launchAgentIdentifier), fmt.Sprintf("/tmp/%s.err.log", launchAgentIdentifier))
+
+	logger.Infof("Outputs are logged to %s and %s", stderrPath(), stdoutPath())
 	return runCommand("launchctl", "load", plistPath)
 }
 
 func uninstallLaunchd(c *cli.Context) error {
-	Log.Infof("Uninstalling Argo Tunnel as an user launch agent")
+
+	if isRootUser() {
+		logger.Infof("Uninstalling Argo Tunnel as a system launch daemon")
+	} else {
+		logger.Infof("Uninstalling Argo Tunnel as an user launch agent")
+	}
 	plistPath, err := launchdTemplate.ResolvePath()
 	if err != nil {
-		Log.WithError(err).Infof("error resolving launchd template path")
+		logger.WithError(err).Infof("error resolving launchd template path")
 		return err
 	}
 	err = runCommand("launchctl", "unload", plistPath)
 	if err != nil {
-		Log.WithError(err).Infof("error unloading")
+		logger.WithError(err).Infof("error unloading")
 		return err
 	}
-	Log.Infof("Outputs are logged in %s and %s", fmt.Sprintf("/tmp/%s.out.log", launchAgentIdentifier), fmt.Sprintf("/tmp/%s.err.log", launchAgentIdentifier))
+
+	logger.Infof("Outputs are logged to %s and %s", stderrPath(), stdoutPath())
 	return launchdTemplate.Remove()
 }
diff --git a/cmd/cloudflared/main.go b/cmd/cloudflared/main.go
index 6d93fdc8..c0b6ebb1 100644
--- a/cmd/cloudflared/main.go
+++ b/cmd/cloudflared/main.go
@@ -11,12 +11,12 @@ import (
 	"os"
 	"os/signal"
 	"path/filepath"
-	"runtime"
 	"strings"
 	"sync"
 	"syscall"
 	"time"
 
+	"github.com/cloudflare/cloudflared/log"
 	"github.com/cloudflare/cloudflared/metrics"
 	"github.com/cloudflare/cloudflared/origin"
 	"github.com/cloudflare/cloudflared/tlsconfig"
@@ -48,7 +48,7 @@ const (
 var listeners = gracenet.Net{}
 var Version = "DEV"
 var BuildTime = "unknown"
-var Log *logrus.Logger
+var logger = log.CreateLogger()
 var defaultConfigFiles = []string{"config.yml", "config.yaml"}
 
 // Launchd doesn't set root env variables, so there is default
@@ -59,15 +59,6 @@ var defaultConfigDirs = []string{"~/.cloudflared", "~/.cloudflare-warp", "~/clou
 // May be closed by the Windows service runner.
 var shutdownC chan struct{}
 
-type BuildAndRuntimeInfo struct {
-	GoOS        string                 `json:"go_os"`
-	GoVersion   string                 `json:"go_version"`
-	GoArch      string                 `json:"go_arch"`
-	WarpVersion string                 `json:"warp_version"`
-	WarpFlags   map[string]interface{} `json:"warp_flags"`
-	WarpEnvs    map[string]string      `json:"warp_envs"`
-}
-
 func main() {
 	metrics.RegisterBuildInfo(BuildTime, Version)
 	raven.SetDSN(sentryDSN)
@@ -306,18 +297,17 @@ func main() {
 		return nil
 	}
 	app.Before = func(context *cli.Context) error {
-		Log = logrus.New()
 		inputSource, err := findInputSourceContext(context)
 		if err != nil {
-			Log.WithError(err).Infof("Cannot load configuration from %s", context.String("config"))
+			logger.WithError(err).Infof("Cannot load configuration from %s", context.String("config"))
 			return err
 		} else if inputSource != nil {
 			err := altsrc.ApplyInputSourceValues(context, inputSource, app.Flags)
 			if err != nil {
-				Log.WithError(err).Infof("Cannot apply configuration from %s", context.String("config"))
+				logger.WithError(err).Infof("Cannot apply configuration from %s", context.String("config"))
 				return err
 			}
-			Log.Infof("Applied configuration from %s", context.String("config"))
+			logger.Infof("Applied configuration from %s", context.String("config"))
 		}
 		return nil
 	}
@@ -404,45 +394,50 @@ func startServer(c *cli.Context) {
 	// c.NumFlags() == 0 && c.NArg() == 0. For cloudflared to work, the user needs to at
 	// least provide a hostname.
 	if c.NumFlags() == 0 && c.NArg() == 0 && os.Getenv("TUNNEL_HOSTNAME") == "" {
-		Log.Infof("No arguments were provided. You need to at least specify the hostname for this tunnel. See %s", quickStartUrl)
+		logger.Infof("No arguments were provided. You need to at least specify the hostname for this tunnel. See %s", quickStartUrl)
 		cli.ShowAppHelp(c)
 		return
 	}
 	logLevel, err := logrus.ParseLevel(c.String("loglevel"))
 	if err != nil {
-		Log.WithError(err).Fatal("Unknown logging level specified")
+		logger.WithError(err).Fatal("Unknown logging level specified")
 	}
-	Log.SetLevel(logLevel)
+	logger.SetLevel(logLevel)
 
 	protoLogLevel, err := logrus.ParseLevel(c.String("proto-loglevel"))
 	if err != nil {
-		Log.WithError(err).Fatal("Unknown protocol logging level specified")
+		logger.WithError(err).Fatal("Unknown protocol logging level specified")
 	}
 	protoLogger := logrus.New()
 	protoLogger.Level = protoLogLevel
 
 	if c.String("logfile") != "" {
 		if err := initLogFile(c, protoLogger); err != nil {
-			Log.Error(err)
+			logger.Error(err)
 		}
 	}
 
+	buildInfo := origin.GetBuildInfo()
+	logger.Infof("Build info: %+v", *buildInfo)
+	logger.Infof("Version %s", Version)
+	logClientOptions(c)
+
 	if c.IsSet("proxy-dns") {
 		port := c.Int("proxy-dns-port")
 		if port <= 0 || port > 65535 {
-			Log.Fatal("The 'proxy-dns-port' must be a valid port number in <1, 65535> range.")
+			logger.Fatal("The 'proxy-dns-port' must be a valid port number in <1, 65535> range.")
 		}
 		wg.Add(1)
 		listener, err := tunneldns.CreateListener(c.String("proxy-dns-address"), uint16(port), c.StringSlice("proxy-dns-upstream"))
 		if err != nil {
 			close(dnsReadySignal)
 			listener.Stop()
-			Log.WithError(err).Fatal("Cannot create the DNS over HTTPS proxy server")
+			logger.WithError(err).Fatal("Cannot create the DNS over HTTPS proxy server")
 		}
 		go func() {
 			err := listener.Start(dnsReadySignal)
 			if err != nil {
-				Log.WithError(err).Fatal("Cannot start the DNS over HTTPS proxy server")
+				logger.WithError(err).Fatal("Cannot start the DNS over HTTPS proxy server")
 			} else {
 				<-shutdownC
 			}
@@ -453,13 +448,14 @@ func startServer(c *cli.Context) {
 		close(dnsReadySignal)
 	}
 
-	if isAutoupdateEnabled(c) {
+	isRunningFromTerminal := isRunningFromTerminal()
+	if isAutoupdateEnabled(c, isRunningFromTerminal) {
 		// Wait for proxy-dns to come up (if used)
 		<-dnsReadySignal
 		if initUpdate() {
 			return
 		}
-		Log.Infof("Autoupdate frequency is set to %v", c.Duration("autoupdate-freq"))
+		logger.Infof("Autoupdate frequency is set to %v", c.Duration("autoupdate-freq"))
 		go autoupdate(c.Duration("autoupdate-freq"), shutdownC)
 	}
 
@@ -473,7 +469,7 @@ func startServer(c *cli.Context) {
 
 	hostname, err := validation.ValidateHostname(c.String("hostname"))
 	if err != nil {
-		Log.WithError(err).Fatal("Invalid hostname")
+		logger.WithError(err).Fatal("Invalid hostname")
 	}
 	clientID := c.String("id")
 	if !c.IsSet("id") {
@@ -482,7 +478,7 @@ func startServer(c *cli.Context) {
 
 	tags, err := NewTagSliceFromCLI(c.StringSlice("tag"))
 	if err != nil {
-		Log.WithError(err).Fatal("Tag parse failure")
+		logger.WithError(err).Fatal("Tag parse failure")
 	}
 
 	tags = append(tags, tunnelpogs.Tag{Name: "ID", Value: clientID})
@@ -491,7 +487,7 @@ func startServer(c *cli.Context) {
 		listener, err := createListener("127.0.0.1:")
 		if err != nil {
 			listener.Close()
-			Log.WithError(err).Fatal("Cannot start Hello World Server")
+			logger.WithError(err).Fatal("Cannot start Hello World Server")
 		}
 		go func() {
 			startHelloWorldServer(listener, shutdownC)
@@ -503,26 +499,26 @@ func startServer(c *cli.Context) {
 
 	url, err := validateUrl(c)
 	if err != nil {
-		Log.WithError(err).Fatal("Error validating url")
+		logger.WithError(err).Fatal("Error validating url")
 	}
-	Log.Infof("Proxying tunnel requests to %s", url)
+	logger.Infof("Proxying tunnel requests to %s", url)
 
 	// Fail if the user provided an old authentication method
 	if c.IsSet("api-key") || c.IsSet("api-email") || c.IsSet("api-ca-key") {
-		Log.Fatal("You don't need to give us your api-key anymore. Please use the new log in method. Just run cloudflared login")
+		logger.Fatal("You don't need to give us your api-key anymore. Please use the new log in method. Just run cloudflared login")
 	}
 
 	// Check that the user has acquired a certificate using the log in command
 	originCertPath, err := homedir.Expand(c.String("origincert"))
 	if err != nil {
-		Log.WithError(err).Fatalf("Cannot resolve path %s", c.String("origincert"))
+		logger.WithError(err).Fatalf("Cannot resolve path %s", c.String("origincert"))
 	}
 	ok, err := fileExists(originCertPath)
 	if err != nil {
-		Log.Fatalf("Cannot check if origin cert exists at path %s", c.String("origincert"))
+		logger.Fatalf("Cannot check if origin cert exists at path %s", c.String("origincert"))
 	}
 	if !ok {
-		Log.Fatalf(`Cannot find a valid certificate for your origin at the path:
+		logger.Fatalf(`Cannot find a valid certificate for your origin at the path:
 
     %s
 
@@ -535,7 +531,7 @@ If you don't have a certificate signed by Cloudflare, run the command:
 	// Easier to send the certificate as []byte via RPC than decoding it at this point
 	originCert, err := ioutil.ReadFile(originCertPath)
 	if err != nil {
-		Log.WithError(err).Fatalf("Cannot read %s to load origin certificate", originCertPath)
+		logger.WithError(err).Fatalf("Cannot read %s to load origin certificate", originCertPath)
 	}
 
 	tunnelMetrics := origin.NewTunnelMetrics()
@@ -558,27 +554,29 @@ If you don't have a certificate signed by Cloudflare, run the command:
 	}
 
 	tunnelConfig := &origin.TunnelConfig{
-		EdgeAddrs:           c.StringSlice("edge"),
-		OriginUrl:           url,
-		Hostname:            hostname,
-		OriginCert:          originCert,
-		TlsConfig:           tlsconfig.CreateTunnelConfig(c, c.StringSlice("edge")),
-		ClientTlsConfig:     httpTransport.TLSClientConfig,
-		Retries:             c.Uint("retries"),
-		HeartbeatInterval:   c.Duration("heartbeat-interval"),
-		MaxHeartbeats:       c.Uint64("heartbeat-count"),
-		ClientID:            clientID,
-		ReportedVersion:     Version,
-		LBPool:              c.String("lb-pool"),
-		Tags:                tags,
-		HAConnections:       c.Int("ha-connections"),
-		HTTPTransport:       httpTransport,
-		Metrics:             tunnelMetrics,
-		MetricsUpdateFreq:   c.Duration("metrics-update-freq"),
-		ProtocolLogger:      protoLogger,
-		Logger:              Log,
-		IsAutoupdated:       c.Bool("is-autoupdated"),
-		GracePeriod:         c.Duration("grace-period"),
+		EdgeAddrs:         c.StringSlice("edge"),
+		OriginUrl:         url,
+		Hostname:          hostname,
+		OriginCert:        originCert,
+		TlsConfig:         tlsconfig.CreateTunnelConfig(c, c.StringSlice("edge")),
+		ClientTlsConfig:   httpTransport.TLSClientConfig,
+		Retries:           c.Uint("retries"),
+		HeartbeatInterval: c.Duration("heartbeat-interval"),
+		MaxHeartbeats:     c.Uint64("heartbeat-count"),
+		ClientID:          clientID,
+		BuildInfo:         buildInfo,
+		ReportedVersion:   Version,
+		LBPool:            c.String("lb-pool"),
+		Tags:              tags,
+		HAConnections:     c.Int("ha-connections"),
+		HTTPTransport:     httpTransport,
+		Metrics:           tunnelMetrics,
+		MetricsUpdateFreq: c.Duration("metrics-update-freq"),
+		ProtocolLogger:    protoLogger,
+		Logger:            logger,
+		IsAutoupdated:     c.Bool("is-autoupdated"),
+		GracePeriod:       c.Duration("grace-period"),
+		RunFromTerminal:   isRunningFromTerminal,
 	}
 
 	go writePidFile(connectedSignal, c.String("pidfile"))
@@ -595,21 +593,21 @@ func runServer(c *cli.Context, wg *sync.WaitGroup, errC chan error, shutdownC ch
 	wg.Add(1)
 	metricsListener, err := listeners.Listen("tcp", c.String("metrics"))
 	if err != nil {
-		Log.WithError(err).Fatal("Error opening metrics server listener")
+		logger.WithError(err).Fatal("Error opening metrics server listener")
 	}
 	go func() {
-		errC <- metrics.ServeMetrics(metricsListener, shutdownC)
+		errC <- metrics.ServeMetrics(metricsListener, shutdownC, logger)
 		wg.Done()
 	}()
 
 	var errCode int
 	err = WaitForSignal(errC, shutdownC)
 	if err != nil {
-		Log.WithError(err).Fatal("Quitting due to error")
+		logger.WithError(err).Fatal("Quitting due to error")
 		raven.CaptureErrorAndWait(err, nil)
 		errCode = 1
 	} else {
-		Log.Info("Graceful shutdown...")
+		logger.Info("Graceful shutdown...")
 	}
 	// Wait for clean exit, discarding all errors
 	go func() {
@@ -648,7 +646,7 @@ func initUpdate() bool {
 	if updateApplied() {
 		os.Args = append(os.Args, "--is-autoupdated=true")
 		if _, err := listeners.StartProcess(); err != nil {
-			Log.WithError(err).Error("Unable to restart server automatically")
+			logger.WithError(err).Error("Unable to restart server automatically")
 			return false
 		}
 		return true
@@ -661,7 +659,7 @@ func autoupdate(freq time.Duration, shutdownC chan struct{}) {
 		if updateApplied() {
 			os.Args = append(os.Args, "--is-autoupdated=true")
 			if _, err := listeners.StartProcess(); err != nil {
-				Log.WithError(err).Error("Unable to restart server automatically")
+				logger.WithError(err).Error("Unable to restart server automatically")
 			}
 			close(shutdownC)
 			return
@@ -673,11 +671,11 @@ func autoupdate(freq time.Duration, shutdownC chan struct{}) {
 func updateApplied() bool {
 	releaseInfo := checkForUpdates()
 	if releaseInfo.Updated {
-		Log.Infof("Updated to version %s", releaseInfo.Version)
+		logger.Infof("Updated to version %s", releaseInfo.Version)
 		return true
 	}
 	if releaseInfo.Error != nil {
-		Log.WithError(releaseInfo.Error).Error("Update check failed")
+		logger.WithError(releaseInfo.Error).Error("Update check failed")
 	}
 	return false
 }
@@ -748,7 +746,7 @@ func writePidFile(waitForSignal chan struct{}, pidFile string) {
 	}
 	file, err := os.Create(pidFile)
 	if err != nil {
-		Log.WithError(err).Errorf("Unable to write pid to %s", pidFile)
+		logger.WithError(err).Errorf("Unable to write pid to %s", pidFile)
 	}
 	defer file.Close()
 	fmt.Fprintf(file, "%d", os.Getpid())
@@ -790,16 +788,22 @@ func initLogFile(c *cli.Context, protoLogger *logrus.Logger) error {
 		logrus.PanicLevel: filePath,
 	}
 
-	Log.Hooks.Add(lfshook.NewHook(pathMap, &logrus.JSONFormatter{}))
+	logger.Hooks.Add(lfshook.NewHook(pathMap, &logrus.JSONFormatter{}))
 	protoLogger.Hooks.Add(lfshook.NewHook(pathMap, &logrus.JSONFormatter{}))
 
-	flags := make(map[string]interface{})
-	envs := make(map[string]string)
+	return nil
+}
 
+func logClientOptions(c *cli.Context) {
+	flags := make(map[string]interface{})
 	for _, flag := range c.LocalFlagNames() {
 		flags[flag] = c.Generic(flag)
 	}
+	if len(flags) > 0 {
+		logger.Infof("Flags %v", flags)
+	}
 
+	envs := make(map[string]string)
 	// Find env variables for Argo Tunnel
 	for _, env := range os.Environ() {
 		// All Argo Tunnel env variables start with TUNNEL_
@@ -810,24 +814,33 @@ func initLogFile(c *cli.Context, protoLogger *logrus.Logger) error {
 			}
 		}
 	}
-
-	Log.Infof("Argo Tunnel build and runtime configuration: %+v", BuildAndRuntimeInfo{
-		GoOS:        runtime.GOOS,
-		GoVersion:   runtime.Version(),
-		GoArch:      runtime.GOARCH,
-		WarpVersion: Version,
-		WarpFlags:   flags,
-		WarpEnvs:    envs,
-	})
-
-	return nil
+	if len(envs) > 0 {
+		logger.Infof("Environmental variables %v", envs)
+	}
 }
 
-func isAutoupdateEnabled(c *cli.Context) bool {
-	if terminal.IsTerminal(int(os.Stdout.Fd())) {
-		Log.Info(noAutoupdateMessage)
+func isAutoupdateEnabled(c *cli.Context, isRunningFromTerminal bool) bool {
+	if isRunningFromTerminal {
+		logger.Info(noAutoupdateMessage)
 		return false
 	}
 
 	return !c.Bool("no-autoupdate") && c.Duration("autoupdate-freq") != 0
 }
+
+
+func isRunningFromTerminal() bool {
+	return terminal.IsTerminal(int(os.Stdout.Fd()))
+}
+
+func userHomeDir() string {
+	// This returns the home dir of the executing user using OS-specific method
+	// for discovering the home dir. It's not recommended to call this function
+	// when the user has root permission as $HOME depends on what options the user
+	// use with sudo.
+	homeDir, err := homedir.Dir()
+	if err != nil {
+		logger.WithError(err).Fatal("Cannot determine home directory for the user.")
+	}
+	return homeDir
+}
diff --git a/cmd/cloudflared/service_template.go b/cmd/cloudflared/service_template.go
index 063e26cb..afec0fd7 100644
--- a/cmd/cloudflared/service_template.go
+++ b/cmd/cloudflared/service_template.go
@@ -73,21 +73,21 @@ func runCommand(command string, args ...string) error {
 	cmd := exec.Command(command, args...)
 	stderr, err := cmd.StderrPipe()
 	if err != nil {
-		Log.WithError(err).Infof("error getting stderr pipe")
+		logger.WithError(err).Infof("error getting stderr pipe")
 		return fmt.Errorf("error getting stderr pipe: %v", err)
 	}
 	err = cmd.Start()
 	if err != nil {
-		Log.WithError(err).Infof("error starting %s", command)
+		logger.WithError(err).Infof("error starting %s", command)
 		return fmt.Errorf("error starting %s: %v", command, err)
 	}
 	commandErr, _ := ioutil.ReadAll(stderr)
 	if len(commandErr) > 0 {
-		Log.Errorf("%s: %s", command, commandErr)
+		logger.Errorf("%s: %s", command, commandErr)
 	}
 	err = cmd.Wait()
 	if err != nil {
-		Log.WithError(err).Infof("%s returned error", command)
+		logger.WithError(err).Infof("%s returned error", command)
 		return fmt.Errorf("%s returned with error: %v", command, err)
 	}
 	return nil
@@ -159,7 +159,7 @@ func copyCredentials(serviceConfigDir, defaultConfigDir, defaultConfigFile strin
 	destConfigPath := filepath.Join(serviceConfigDir, defaultConfigFile)
 	destFile, exists, err := openFile(destConfigPath, true)
 	if err != nil {
-		Log.WithError(err).Infof("cannot open %s", destConfigPath)
+		logger.WithError(err).Infof("cannot open %s", destConfigPath)
 		return err
 	} else if exists {
 		// config already exists, do nothing
@@ -185,7 +185,7 @@ func copyCredentials(serviceConfigDir, defaultConfigDir, defaultConfigFile strin
 		if err != nil {
 			return fmt.Errorf("unable to copy %s to %s: %v", srcConfigPath, destConfigPath, err)
 		}
-		Log.Infof("Copied %s to %s", srcConfigPath, destConfigPath)
+		logger.Infof("Copied %s to %s", srcConfigPath, destConfigPath)
 	}
 
 	return nil
diff --git a/cmd/cloudflared/windows_service.go b/cmd/cloudflared/windows_service.go
index b003bb50..f1442863 100644
--- a/cmd/cloudflared/windows_service.go
+++ b/cmd/cloudflared/windows_service.go
@@ -41,7 +41,7 @@ func runApp(app *cli.App) {
 
 	isIntSess, err := svc.IsAnInteractiveSession()
 	if err != nil {
-		Log.Fatalf("failed to determine if we are running in an interactive session: %v", err)
+		logger.Fatalf("failed to determine if we are running in an interactive session: %v", err)
 	}
 
 	if isIntSess {
@@ -51,7 +51,7 @@ func runApp(app *cli.App) {
 
 	elog, err := eventlog.Open(windowsServiceName)
 	if err != nil {
-		Log.WithError(err).Infof("Cannot open event log for %s", windowsServiceName)
+		logger.WithError(err).Infof("Cannot open event log for %s", windowsServiceName)
 		return
 	}
 	defer elog.Close()
@@ -104,62 +104,62 @@ loop:
 }
 
 func installWindowsService(c *cli.Context) error {
-	Log.Infof("Installing Argo Tunnel Windows service")
+	logger.Infof("Installing Argo Tunnel Windows service")
 	exepath, err := os.Executable()
 	if err != nil {
-		Log.Infof("Cannot find path name that start the process")
+		logger.Infof("Cannot find path name that start the process")
 		return err
 	}
 	m, err := mgr.Connect()
 	if err != nil {
-		Log.WithError(err).Infof("Cannot establish a connection to the service control manager")
+		logger.WithError(err).Infof("Cannot establish a connection to the service control manager")
 		return err
 	}
 	defer m.Disconnect()
 	s, err := m.OpenService(windowsServiceName)
 	if err == nil {
 		s.Close()
-		Log.Errorf("service %s already exists", windowsServiceName)
+		logger.Errorf("service %s already exists", windowsServiceName)
 		return fmt.Errorf("service %s already exists", windowsServiceName)
 	}
 	config := mgr.Config{StartType: mgr.StartAutomatic, DisplayName: windowsServiceDescription}
 	s, err = m.CreateService(windowsServiceName, exepath, config)
 	if err != nil {
-		Log.Infof("Cannot install service %s", windowsServiceName)
+		logger.Infof("Cannot install service %s", windowsServiceName)
 		return err
 	}
 	defer s.Close()
 	err = eventlog.InstallAsEventCreate(windowsServiceName, eventlog.Error|eventlog.Warning|eventlog.Info)
 	if err != nil {
 		s.Delete()
-		Log.WithError(err).Infof("Cannot install event logger")
+		logger.WithError(err).Infof("Cannot install event logger")
 		return fmt.Errorf("SetupEventLogSource() failed: %s", err)
 	}
 	return nil
 }
 
 func uninstallWindowsService(c *cli.Context) error {
-	Log.Infof("Uninstalling Argo Tunnel Windows Service")
+	logger.Infof("Uninstalling Argo Tunnel Windows Service")
 	m, err := mgr.Connect()
 	if err != nil {
-		Log.Infof("Cannot establish a connection to the service control manager")
+		logger.Infof("Cannot establish a connection to the service control manager")
 		return err
 	}
 	defer m.Disconnect()
 	s, err := m.OpenService(windowsServiceName)
 	if err != nil {
-		Log.Infof("service %s is not installed", windowsServiceName)
+		logger.Infof("service %s is not installed", windowsServiceName)
 		return fmt.Errorf("service %s is not installed", windowsServiceName)
 	}
 	defer s.Close()
 	err = s.Delete()
 	if err != nil {
-		Log.Errorf("Cannot delete service %s", windowsServiceName)
+		logger.Errorf("Cannot delete service %s", windowsServiceName)
 		return err
 	}
 	err = eventlog.Remove(windowsServiceName)
 	if err != nil {
-		Log.Infof("Cannot remove event logger")
+		logger.Infof("Cannot remove event logger")
 		return fmt.Errorf("RemoveEventLogSource() failed: %s", err)
 	}
 	return nil
diff --git a/log/log.go b/log/log.go
new file mode 100644
index 00000000..f1824f2e
--- /dev/null
+++ b/log/log.go
@@ -0,0 +1,85 @@
+// this forks the logrus json formatter to rename msg -> message as that's the
+// expected field. Ideally the logger should make it easier for us.
+package log
+
+import (
+	"encoding/json"
+	"fmt"
+	"time"
+
+	"github.com/mattn/go-colorable"
+	"github.com/sirupsen/logrus"
+)
+
+var (
+	DefaultTimestampFormat = time.RFC3339
+)
+
+type JSONFormatter struct {
+	// TimestampFormat sets the format used for marshaling timestamps.
+	TimestampFormat string
+}
+
+func CreateLogger() *logrus.Logger {
+	logger := logrus.New()
+	logger.Out = colorable.NewColorableStderr()
+	logger.Formatter = &logrus.TextFormatter{ForceColors: true}
+
+	return logger
+}
+
+func (f *JSONFormatter) Format(entry *logrus.Entry) ([]byte, error) {
+	data := make(logrus.Fields, len(entry.Data)+3)
+	for k, v := range entry.Data {
+		switch v := v.(type) {
+		case error:
+			// Otherwise errors are ignored by `encoding/json`
+			// https://github.com/sirupsen/logrus/issues/137
+			data[k] = v.Error()
+		default:
+			data[k] = v
+		}
+	}
+	prefixFieldClashes(data)
+
+	timestampFormat := f.TimestampFormat
+	if timestampFormat == "" {
+		timestampFormat = DefaultTimestampFormat
+	}
+
+	data["time"] = entry.Time.Format(timestampFormat)
+	data["message"] = entry.Message
+	data["level"] = entry.Level.String()
+
+	serialized, err := json.Marshal(data)
+	if err != nil {
+		return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
+	}
+	return append(serialized, '\n'), nil
+}
+
+// This is to not silently overwrite `time`, `msg` and `level` fields when
+// dumping it. If this code wasn't there doing:
+//
+//  logrus.WithField("level", 1).Info("hello")
+//
+// Would just silently drop the user provided level. Instead with this code
+// it'll logged as:
+//
+//  {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."}
+//
+// It's not exported because it's still using Data in an opinionated way. It's to
+// avoid code duplication between the two default formatters.
+func prefixFieldClashes(data logrus.Fields) {
+	if t, ok := data["time"]; ok {
+		data["fields.time"] = t
+	}
+
+	if m, ok := data["msg"]; ok {
+		data["fields.msg"] = m
+	}
+
+	if l, ok := data["level"]; ok {
+		data["fields.level"] = l
+	}
+}
diff --git a/metrics/metrics.go b/metrics/metrics.go
index 4707b4ed..4b6156ab 100644
--- a/metrics/metrics.go
+++ b/metrics/metrics.go
@@ -13,7 +13,7 @@ import (
 
 	"github.com/prometheus/client_golang/prometheus"
 	"github.com/prometheus/client_golang/prometheus/promhttp"
-	log "github.com/sirupsen/logrus"
+	"github.com/sirupsen/logrus"
 )
 
 const (
@@ -21,7 +21,7 @@ const (
 	startupTime     = time.Millisecond * 500
 )
 
-func ServeMetrics(l net.Listener, shutdownC <-chan struct{}) (err error) {
+func ServeMetrics(l net.Listener, shutdownC <-chan struct{}, logger *logrus.Logger) (err error) {
 	var wg sync.WaitGroup
 	// Metrics port is privileged, so no need for further access control
 	trace.AuthRequest = func(*http.Request) (bool, bool) { return true, true }
@@ -39,7 +39,7 @@ func ServeMetrics(l net.Listener, shutdownC <-chan struct{}) (err error) {
 		defer wg.Done()
 		err = server.Serve(l)
 	}()
-	log.WithField("addr", l.Addr()).Info("Starting metrics server")
+	logger.WithField("addr", l.Addr()).Info("Starting metrics server")
 	// server.Serve will hang if server.Shutdown is called before the server is
 	// fully started up. So add artificial delay.
 	time.Sleep(startupTime)
@@ -51,10 +51,10 @@ func ServeMetrics(l net.Listener, shutdownC <-chan struct{}) (err error) {
 
 	wg.Wait()
 	if err == http.ErrServerClosed {
-		log.Info("Metrics server stopped")
+		logger.Info("Metrics server stopped")
 		return nil
 	}
-	log.WithError(err).Error("Metrics server quit with error")
+	logger.WithError(err).Error("Metrics server quit with error")
 	return err
 }
 
diff --git a/origin/build_info.go b/origin/build_info.go
new file mode 100644
index 00000000..72f0965a
--- /dev/null
+++ b/origin/build_info.go
@@ -0,0 +1,19 @@
+package origin
+
+import (
+	"runtime"
+)
+
+type BuildInfo struct {
+	GoOS               string `json:"go_os"`
+	GoVersion          string `json:"go_version"`
+	GoArch             string `json:"go_arch"`
+}
+
+func GetBuildInfo() *BuildInfo {
+	return &BuildInfo{
+		GoOS:      runtime.GOOS,
+		GoVersion: runtime.Version(),
+		GoArch:    runtime.GOARCH,
+	}
+}
diff --git a/origin/metrics.go b/origin/metrics.go
index 9908c554..8ee560c1 100644
--- a/origin/metrics.go
+++ b/origin/metrics.go
@@ -27,7 +27,7 @@ type muxerMetrics struct {
 	outBoundRateMax  *prometheus.GaugeVec
 }
 
-type tunnelMetrics struct {
+type TunnelMetrics struct {
 	haConnections     prometheus.Gauge
 	totalRequests     prometheus.Counter
 	requestsPerTunnel *prometheus.CounterVec
@@ -229,7 +229,7 @@ func convertRTTMilliSec(t time.Duration) float64 {
 }
 
 // Metrics that can be collected without asking the edge
-func NewTunnelMetrics() *tunnelMetrics {
+func NewTunnelMetrics() *TunnelMetrics {
 	haConnections := prometheus.NewGauge(
 		prometheus.GaugeOpts{
 			Name: "ha_connections",
@@ -305,7 +305,7 @@ func NewTunnelMetrics() *tunnelMetrics {
 	)
 	prometheus.MustRegister(serverLocations)
 
-	return &tunnelMetrics{
+	return &TunnelMetrics{
 		haConnections:                  haConnections,
 		totalRequests:                  totalRequests,
 		requestsPerTunnel:              requestsPerTunnel,
@@ -322,19 +322,19 @@ func NewTunnelMetrics() *tunnelMetrics {
 	}
 }
 
-func (t *tunnelMetrics) incrementHaConnections() {
+func (t *TunnelMetrics) incrementHaConnections() {
 	t.haConnections.Inc()
 }
 
-func (t *tunnelMetrics) decrementHaConnections() {
+func (t *TunnelMetrics) decrementHaConnections() {
 	t.haConnections.Dec()
 }
 
-func (t *tunnelMetrics) updateMuxerMetrics(connectionID string, metrics *h2mux.MuxerMetrics) {
+func (t *TunnelMetrics) updateMuxerMetrics(connectionID string, metrics *h2mux.MuxerMetrics) {
 	t.muxerMetrics.update(connectionID, metrics)
 }
 
-func (t *tunnelMetrics) incrementRequests(connectionID string) {
+func (t *TunnelMetrics) incrementRequests(connectionID string) {
 	t.concurrentRequestsLock.Lock()
 	var concurrentRequests uint64
 	var ok bool
@@ -356,25 +356,25 @@ func (t *tunnelMetrics) incrementRequests(connectionID string) {
 	t.concurrentRequestsPerTunnel.WithLabelValues(connectionID).Inc()
 }
 
-func (t *tunnelMetrics) decrementConcurrentRequests(connectionID string) {
+func (t *TunnelMetrics) decrementConcurrentRequests(connectionID string) {
 	t.concurrentRequestsLock.Lock()
 	if _, ok := t.concurrentRequests[connectionID]; ok {
 		t.concurrentRequests[connectionID] -= 1
 	} else {
-		Log.Error("Concurrent requests per tunnel metrics went wrong; you can't decrement concurrent requests count without increment it first.")
+		logger.Error("Concurrent requests per tunnel metrics went wrong; you can't decrement concurrent requests count without increment it first.")
 	}
 	t.concurrentRequestsLock.Unlock()
 
 	t.concurrentRequestsPerTunnel.WithLabelValues(connectionID).Dec()
 }
 
-func (t *tunnelMetrics) incrementResponses(connectionID, code string) {
+func (t *TunnelMetrics) incrementResponses(connectionID, code string) {
 	t.responseByCode.WithLabelValues(code).Inc()
 	t.responseCodePerTunnel.WithLabelValues(connectionID, code).Inc()
 
 }
 
-func (t *tunnelMetrics) registerServerLocation(connectionID, loc string) {
+func (t *TunnelMetrics) registerServerLocation(connectionID, loc string) {
 	t.locationLock.Lock()
 	defer t.locationLock.Unlock()
 	if oldLoc, ok := t.oldServerLocations[connectionID]; ok && oldLoc == loc {
diff --git a/origin/supervisor.go b/origin/supervisor.go
index 4deb57c4..9a315ad8 100644
--- a/origin/supervisor.go
+++ b/origin/supervisor.go
@@ -73,7 +73,7 @@ func (s *Supervisor) Run(ctx context.Context, connectedSignal chan struct{}) err
 		case tunnelError := <-s.tunnelErrors:
 			tunnelsActive--
 			if tunnelError.err != nil {
-				Log.WithError(tunnelError.err).Warn("Tunnel disconnected due to error")
+				logger.WithError(tunnelError.err).Warn("Tunnel disconnected due to error")
 				tunnelsWaiting = append(tunnelsWaiting, tunnelError.index)
 				s.waitForNextTunnel(tunnelError.index)
 
@@ -109,10 +109,10 @@ func (s *Supervisor) Run(ctx context.Context, connectedSignal chan struct{}) err
 			s.lastResolve = time.Now()
 			s.resolverC = nil
 			if result.err == nil {
-				Log.Debug("Service discovery refresh complete")
+				logger.Debug("Service discovery refresh complete")
 				s.edgeIPs = result.edgeIPs
 			} else {
-				Log.WithError(result.err).Error("Service discovery error")
+				logger.WithError(result.err).Error("Service discovery error")
 			}
 		}
 	}
@@ -121,12 +121,12 @@ func (s *Supervisor) Run(ctx context.Context, connectedSignal chan struct{}) err
 func (s *Supervisor) initialize(ctx context.Context, connectedSignal chan struct{}) error {
 	edgeIPs, err := ResolveEdgeIPs(s.config.EdgeAddrs)
 	if err != nil {
-		Log.Infof("ResolveEdgeIPs err")
+		logger.Infof("ResolveEdgeIPs err")
 		return err
 	}
 	s.edgeIPs = edgeIPs
 	if s.config.HAConnections > len(edgeIPs) {
-		Log.Warnf("You requested %d HA connections but I can give you at most %d.", s.config.HAConnections, len(edgeIPs))
+		logger.Warnf("You requested %d HA connections but I can give you at most %d.", s.config.HAConnections, len(edgeIPs))
 		s.config.HAConnections = len(edgeIPs)
 	}
 	s.lastResolve = time.Now()
diff --git a/origin/tunnel.go b/origin/tunnel.go
index 96d06469..8257d3d1 100644
--- a/origin/tunnel.go
+++ b/origin/tunnel.go
@@ -7,7 +7,6 @@ import (
 	"net"
 	"net/http"
 	"net/url"
-	"runtime"
 	"strconv"
 	"strings"
 	"sync"
@@ -28,7 +27,7 @@ import (
 	rpc "zombiezen.com/go/capnproto2/rpc"
 )
 
-var Log *logrus.Logger
+var logger *logrus.Logger
 
 const (
 	dialTimeout = 15 * time.Second
@@ -48,17 +47,19 @@ type TunnelConfig struct {
 	HeartbeatInterval time.Duration
 	MaxHeartbeats     uint64
 	ClientID          string
+	BuildInfo         *BuildInfo
 	ReportedVersion   string
 	LBPool            string
 	Tags              []tunnelpogs.Tag
 	HAConnections     int
 	HTTPTransport     http.RoundTripper
-	Metrics           *tunnelMetrics
+	Metrics           *TunnelMetrics
 	MetricsUpdateFreq time.Duration
 	ProtocolLogger    *logrus.Logger
 	Logger            *logrus.Logger
 	IsAutoupdated     bool
 	GracePeriod       time.Duration
+	RunFromTerminal   bool
 }
 
 type dialError struct {
@@ -92,18 +93,19 @@ func (c *TunnelConfig) RegistrationOptions(connectionID uint8, OriginLocalIP str
 	return &tunnelpogs.RegistrationOptions{
 		ClientID:             c.ClientID,
 		Version:              c.ReportedVersion,
-		OS:                   fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH),
+		OS:                   fmt.Sprintf("%s_%s", c.BuildInfo.GoOS, c.BuildInfo.GoArch),
 		ExistingTunnelPolicy: policy,
 		PoolName:             c.LBPool,
 		Tags:                 c.Tags,
 		ConnectionID:         connectionID,
 		OriginLocalIP:        OriginLocalIP,
 		IsAutoupdated:        c.IsAutoupdated,
+		RunFromTerminal:      c.RunFromTerminal,
 	}
 }
 
 func StartTunnelDaemon(config *TunnelConfig, shutdownC <-chan struct{}, connectedSignal chan struct{}) error {
-	Log = config.Logger
+	logger = config.Logger
 	ctx, cancel := context.WithCancel(context.Background())
 	go func() {
 		<-shutdownC
@@ -138,7 +140,7 @@ func ServeTunnelLoop(ctx context.Context, config *TunnelConfig, addr *net.TCPAdd
 		err, recoverable := ServeTunnel(ctx, config, addr, connectionID, connectedFuse, &backoff)
 		if recoverable {
 			if duration, ok := backoff.GetBackoffDuration(ctx); ok {
-				Log.Infof("Retrying in %s seconds", duration)
+				logger.Infof("Retrying in %s seconds", duration)
 				backoff.Backoff(ctx)
 				continue
 			}
@@ -171,7 +173,7 @@ func ServeTunnel(
 	// Returns error from parsing the origin URL or handshake errors
 	handler, originLocalIP, err := NewTunnelHandler(ctx, config, addr.String(), connectionID)
 	if err != nil {
-		errLog := Log.WithError(err)
+		errLog := logger.WithError(err)
 		switch err.(type) {
 		case dialError:
 			errLog.Error("Unable to dial edge")
@@ -218,21 +220,21 @@ func ServeTunnel(
 	registerErr := <-registerErrC
 	wg.Wait()
 	if err != nil {
-		Log.WithError(err).Error("Tunnel error")
+		logger.WithError(err).Error("Tunnel error")
 		return err, true
 	}
 	if registerErr != nil {
 		// Don't retry on errors like entitlement failure or version too old
 		if e, ok := registerErr.(printableRegisterTunnelError); ok {
-			Log.Error(e)
+			logger.Error(e)
 			return e.cause, !e.permanent
 		} else if e, ok := registerErr.(dupConnRegisterTunnelError); ok {
-			Log.Info("Already connected to this server, selecting a different one")
+			logger.Info("Already connected to this server, selecting a different one")
 			return e, true
 		}
 		// Only log errors to Sentry that may have been caused by the client side, to reduce dupes
 		raven.CaptureError(registerErr, nil)
-		Log.Error("Cannot register")
+		logger.Error("Cannot register")
 		return err, true
 	}
 	return nil, false
@@ -249,7 +251,7 @@ func IsRPCStreamResponse(headers []h2mux.Header) bool {
 }
 
 func RegisterTunnel(ctx context.Context, muxer *h2mux.Muxer, config *TunnelConfig, connectionID uint8, originLocalIP string) error {
-	logger := Log.WithField("subsystem", "rpc")
+	logger := logger.WithField("subsystem", "rpc")
 	logger.Debug("initiating RPC stream to register")
 	stream, err := muxer.OpenStream([]h2mux.Header{
 		{Name: ":method", Value: "RPC"},
@@ -304,7 +306,7 @@ func RegisterTunnel(ctx context.Context, muxer *h2mux.Muxer, config *TunnelConfi
 }
 
 func UnregisterTunnel(muxer *h2mux.Muxer, gracePeriod time.Duration) error {
-	logger := Log.WithField("subsystem", "rpc")
+	logger := logger.WithField("subsystem", "rpc")
 	logger.Debug("initiating RPC stream to unregister")
 	stream, err := muxer.OpenStream([]h2mux.Header{
 		{Name: ":method", Value: "RPC"},
@@ -335,7 +337,7 @@ func UnregisterTunnel(muxer *h2mux.Muxer, gracePeriod time.Duration) error {
 func LogServerInfo(logger *logrus.Entry,
 	promise tunnelrpc.ServerInfo_Promise,
 	connectionID uint8,
-	metrics *tunnelMetrics,
+	metrics *TunnelMetrics,
 ) {
 	serverInfoMessage, err := promise.Struct()
 	if err != nil {
@@ -347,7 +349,7 @@ func LogServerInfo(logger *logrus.Entry,
 		logger.WithError(err).Warn("Failed to retrieve server information")
 		return
 	}
-	Log.Infof("Connected to %s", serverInfo.LocationName)
+	logger.Infof("Connected to %s", serverInfo.LocationName)
 	metrics.registerServerLocation(uint8ToString(connectionID), serverInfo.LocationName)
 }
 
@@ -398,7 +400,7 @@ type TunnelHandler struct {
 	httpClient http.RoundTripper
 	tlsConfig  *tls.Config
 	tags       []tunnelpogs.Tag
-	metrics    *tunnelMetrics
+	metrics    *TunnelMetrics
 	// connectionID is only used by metrics, and prometheus requires labels to be string
 	connectionID string
 }
@@ -407,12 +409,12 @@ var dialer = net.Dialer{DualStack: true}
 
 // NewTunnelHandler returns a TunnelHandler, origin LAN IP and error
 func NewTunnelHandler(ctx context.Context, config *TunnelConfig, addr string, connectionID uint8) (*TunnelHandler, string, error) {
-	url, err := validation.ValidateUrl(config.OriginUrl)
+	originURL, err := validation.ValidateUrl(config.OriginUrl)
 	if err != nil {
-		return nil, "", fmt.Errorf("Unable to parse origin url %#v", url)
+		return nil, "", fmt.Errorf("Unable to parse origin url %#v", originURL)
 	}
 	h := &TunnelHandler{
-		originUrl:    url,
+		originUrl:    originURL,
 		httpClient:   config.HTTPTransport,
 		tlsConfig:    config.ClientTlsConfig,
 		tags:         config.Tags,
@@ -464,11 +466,11 @@ func (h *TunnelHandler) ServeStream(stream *h2mux.MuxedStream) error {
 	h.metrics.incrementRequests(h.connectionID)
 	req, err := http.NewRequest("GET", h.originUrl, h2mux.MuxedStreamReader{MuxedStream: stream})
 	if err != nil {
-		Log.WithError(err).Panic("Unexpected error from http.NewRequest")
+		logger.WithError(err).Panic("Unexpected error from http.NewRequest")
 	}
 	err = H2RequestHeadersToH1Request(stream.Headers, req)
 	if err != nil {
-		Log.WithError(err).Error("invalid request received")
+		logger.WithError(err).Error("invalid request received")
 	}
 	h.AppendTagHeaders(req)
 	cfRay := FindCfRayHeader(req)
@@ -501,7 +503,7 @@ func (h *TunnelHandler) ServeStream(stream *h2mux.MuxedStream) error {
 }
 
 func (h *TunnelHandler) logError(stream *h2mux.MuxedStream, err error) {
-	Log.WithError(err).Error("HTTP request error")
+	logger.WithError(err).Error("HTTP request error")
 	stream.WriteHeaders([]h2mux.Header{{Name: ":status", Value: "502"}})
 	stream.Write([]byte("502 Bad Gateway"))
 	h.metrics.incrementResponses(h.connectionID, "502")
@@ -509,20 +511,20 @@ func (h *TunnelHandler) logError(stream *h2mux.MuxedStream, err error) {
 
 func (h *TunnelHandler) logRequest(req *http.Request, cfRay string) {
 	if cfRay != "" {
-		Log.WithField("CF-RAY", cfRay).Infof("%s %s %s", req.Method, req.URL, req.Proto)
+		logger.WithField("CF-RAY", cfRay).Infof("%s %s %s", req.Method, req.URL, req.Proto)
 	} else {
-		Log.Warnf("All requests should have a CF-RAY header. Please open a support ticket with Cloudflare. %s %s %s ", req.Method, req.URL, req.Proto)
+		logger.Warnf("All requests should have a CF-RAY header. Please open a support ticket with Cloudflare. %s %s %s ", req.Method, req.URL, req.Proto)
 	}
-	Log.Debugf("Request Headers %+v", req.Header)
+	logger.Debugf("Request Headers %+v", req.Header)
 }
 
 func (h *TunnelHandler) logResponse(r *http.Response, cfRay string) {
 	if cfRay != "" {
-		Log.WithField("CF-RAY", cfRay).Infof("%s", r.Status)
+		logger.WithField("CF-RAY", cfRay).Infof("%s", r.Status)
 	} else {
-		Log.Infof("%s", r.Status)
+		logger.Infof("%s", r.Status)
 	}
-	Log.Debugf("Response Headers %+v", r.Header)
+	logger.Debugf("Response Headers %+v", r.Header)
 }
 
 func (h *TunnelHandler) UpdateMetrics(connectionID string) {
diff --git a/tlsconfig/tlsconfig.go b/tlsconfig/tlsconfig.go
index d81e94f2..ba76cf97 100644
--- a/tlsconfig/tlsconfig.go
+++ b/tlsconfig/tlsconfig.go
@@ -8,10 +8,12 @@ import (
 	"io/ioutil"
 	"net"
 
-	log "github.com/sirupsen/logrus"
-	cli "gopkg.in/urfave/cli.v2"
+	"github.com/cloudflare/cloudflared/log"
+	"gopkg.in/urfave/cli.v2"
 )
 
+var logger = log.CreateLogger()
+
 // CLIFlags names the flags used to configure TLS for a command or subsystem.
 // The nil value for a field means the flag is ignored.
 type CLIFlags struct {
@@ -29,7 +31,7 @@ func (f CLIFlags) GetConfig(c *cli.Context) *tls.Config {
 	if c.IsSet(f.Cert) && c.IsSet(f.Key) {
 		cert, err := tls.LoadX509KeyPair(c.String(f.Cert), c.String(f.Key))
 		if err != nil {
-			log.WithError(err).Fatal("Error parsing X509 key pair")
+			logger.WithError(err).Fatal("Error parsing X509 key pair")
 		}
 		config.Certificates = []tls.Certificate{cert}
 		config.BuildNameToCertificate()
@@ -53,11 +55,11 @@ func (f CLIFlags) GetConfig(c *cli.Context) *tls.Config {
 func LoadCert(certPath string) *x509.CertPool {
 	caCert, err := ioutil.ReadFile(certPath)
 	if err != nil {
-		log.WithError(err).Fatalf("Error reading certificate %s", certPath)
+		logger.WithError(err).Fatalf("Error reading certificate %s", certPath)
 	}
 	ca := x509.NewCertPool()
 	if !ca.AppendCertsFromPEM(caCert) {
-		log.WithError(err).Fatalf("Error parsing certificate %s", certPath)
+		logger.WithError(err).Fatalf("Error parsing certificate %s", certPath)
 	}
 	return ca
 }
@@ -66,23 +68,23 @@ func LoadOriginCertsPool() *x509.CertPool {
 	// First, obtain the system certificate pool
 	certPool, systemCertPoolErr := x509.SystemCertPool()
 	if systemCertPoolErr != nil {
-		log.Warn("error obtaining the system certificates: %s", systemCertPoolErr)
+		logger.Warnf("error obtaining the system certificates: %s", systemCertPoolErr)
 		certPool = x509.NewCertPool()
 	}
 
 	// Next, append the Cloudflare CA pool into the system pool
 	if !certPool.AppendCertsFromPEM([]byte(cloudflareRootCA)) {
-		log.Warn("could not append the CF certificate to the system certificate pool")
+		logger.Warn("could not append the CF certificate to the system certificate pool")
 
 		if systemCertPoolErr != nil { // Obtaining both certificates failed; this is a fatal error
-			log.WithError(systemCertPoolErr).Fatalf("Error loading the certificate pool")
+			logger.WithError(systemCertPoolErr).Fatalf("Error loading the certificate pool")
 		}
 	}
 
 	// Finally, add the Hello certificate into the pool (since it's self-signed)
 	helloCertificate, err := GetHelloCertificateX509()
 	if err != nil {
-		log.Warn("error obtaining the Hello server certificate")
+		logger.Warn("error obtaining the Hello server certificate")
 	}
 
 	certPool.AddCert(helloCertificate)
diff --git a/tunneldns/tunnel.go b/tunneldns/tunnel.go
index efd1229d..13db1fb6 100644
--- a/tunneldns/tunnel.go
+++ b/tunneldns/tunnel.go
@@ -8,16 +8,18 @@ import (
 	"sync"
 	"syscall"
 
-	"gopkg.in/urfave/cli.v2"
-
+	"github.com/cloudflare/cloudflared/log"
 	"github.com/cloudflare/cloudflared/metrics"
+
 	"github.com/coredns/coredns/core/dnsserver"
 	"github.com/coredns/coredns/plugin"
 	"github.com/coredns/coredns/plugin/cache"
 	"github.com/pkg/errors"
-	log "github.com/sirupsen/logrus"
+	"gopkg.in/urfave/cli.v2"
 )
 
+var logger = log.CreateLogger()
+
 // Listener is an adapter between CoreDNS server and Warp runnable
 type Listener struct {
 	server *dnsserver.Server
@@ -28,14 +30,14 @@ type Listener struct {
 func Run(c *cli.Context) error {
 	metricsListener, err := net.Listen("tcp", c.String("metrics"))
 	if err != nil {
-		log.WithError(err).Fatal("Failed to open the metrics listener")
+		logger.WithError(err).Fatal("Failed to open the metrics listener")
 	}
 
-	go metrics.ServeMetrics(metricsListener, nil)
+	go metrics.ServeMetrics(metricsListener, nil, logger)
 
 	listener, err := CreateListener(c.String("address"), uint16(c.Uint("port")), c.StringSlice("upstream"))
 	if err != nil {
-		log.WithError(err).Errorf("Failed to create the listeners")
+		logger.WithError(err).Errorf("Failed to create the listeners")
 		return err
 	}
 
@@ -43,7 +45,7 @@ func Run(c *cli.Context) error {
 	readySignal := make(chan struct{})
 	err = listener.Start(readySignal)
 	if err != nil {
-		log.WithError(err).Errorf("Failed to start the listeners")
+		logger.WithError(err).Errorf("Failed to start the listeners")
 		return listener.Stop()
 	}
 	<-readySignal
@@ -57,7 +59,7 @@ func Run(c *cli.Context) error {
 	// Shut down server
 	err = listener.Stop()
 	if err != nil {
-		log.WithError(err).Errorf("failed to stop")
+		logger.WithError(err).Errorf("failed to stop")
 	}
 	return err
 }
@@ -78,7 +80,7 @@ func createConfig(address string, port uint16, p plugin.Handler) *dnsserver.Conf
 // Start blocks for serving requests
 func (l *Listener) Start(readySignal chan struct{}) error {
 	defer close(readySignal)
-	log.WithField("addr", l.server.Address()).Infof("Starting DNS over HTTPS proxy server")
+	logger.WithField("addr", l.server.Address()).Infof("Starting DNS over HTTPS proxy server")
 
 	// Start UDP listener
 	if udp, err := l.server.ListenPacket(); err == nil {
@@ -119,7 +121,7 @@ func CreateListener(address string, port uint16, upstreams []string) (*Listener,
 	// Build the list of upstreams
 	upstreamList := make([]Upstream, 0)
 	for _, url := range upstreams {
-		log.WithField("url", url).Infof("Adding DNS upstream")
+		logger.WithField("url", url).Infof("Adding DNS upstream")
 		upstream, err := NewUpstreamHTTPS(url)
 		if err != nil {
 			return nil, errors.Wrap(err, "failed to create HTTPS upstream")
diff --git a/tunnelrpc/pogs/tunnelrpc.go b/tunnelrpc/pogs/tunnelrpc.go
index ab14060a..8d297a2f 100644
--- a/tunnelrpc/pogs/tunnelrpc.go
+++ b/tunnelrpc/pogs/tunnelrpc.go
@@ -52,7 +52,7 @@ type RegistrationOptions struct {
 	ConnectionID         uint8  `capnp:"connectionId"`
 	OriginLocalIP        string `capnp:"originLocalIp"`
 	IsAutoupdated        bool   `capnp:"isAutoupdated"`
-	gracePeriodNanoSec   int64  `capnp:"gracePeriodNanoSec"`
+	RunFromTerminal      bool   `capnp:"runFromTerminal"`
 }
 
 func MarshalRegistrationOptions(s tunnelrpc.RegistrationOptions, p *RegistrationOptions) error {
diff --git a/tunnelrpc/tunnelrpc.capnp b/tunnelrpc/tunnelrpc.capnp
index d90ef200..cbc25755 100644
--- a/tunnelrpc/tunnelrpc.capnp
+++ b/tunnelrpc/tunnelrpc.capnp
@@ -37,6 +37,8 @@ struct RegistrationOptions {
     originLocalIp @7 :Text;
     # whether Argo Tunnel client has been autoupdated
     isAutoupdated @8 :Bool;
+    # whether Argo Tunnel client is run from a terminal
+    runFromTerminal @9 :Bool;
 }
 
 struct Tag {
diff --git a/tunnelrpc/tunnelrpc.capnp.go b/tunnelrpc/tunnelrpc.capnp.go
index 0b54a66b..112b59d1 100644
--- a/tunnelrpc/tunnelrpc.capnp.go
+++ b/tunnelrpc/tunnelrpc.capnp.go
@@ -403,6 +403,14 @@ func (s RegistrationOptions) SetIsAutoupdated(v bool) {
 	s.Struct.SetBit(24, v)
 }
 
+func (s RegistrationOptions) RunFromTerminal() bool {
+	return s.Struct.Bit(25)
+}
+
+func (s RegistrationOptions) SetRunFromTerminal(v bool) {
+	s.Struct.SetBit(25, v)
+}
+
 // RegistrationOptions_List is a list of RegistrationOptions.
 type RegistrationOptions_List struct{ capnp.List }
 
@@ -1218,86 +1226,88 @@ func (p TunnelServer_unregisterTunnel_Results_Promise) Struct() (TunnelServer_un
 	return TunnelServer_unregisterTunnel_Results{s}, err
 }
 
-const schema_db8274f9144abc7e = "x\xda\x9cU_\x88Te\x1b\x7f~\xef;3g\x84" +
-	"]g\x0fg\x04\xbf\xe1\x93\xe5\x93\x15\xff\xe0\xfa\xe9\xa7" +
-	"\xfb\xa1\xdb\x9f\xd9\xdd\xd4\x98m]\xe7\xdd\xd1\x10\xf5\xc2" +
-	"\xe3\xcc\xeb\xec\xd9f\xce\x19\xce9c)\xa4%B " +
-	"$\x96uc\x14\xe4e\x17\x15t\x11\x84\x81\xdd$\xe1" +
-	"\x85\x08\x19EB\x94l\xa1(\xd6\xa2\x90\x91\x9cx\xcf" +
-	"\xec\x999\xae\xa5\xd6\xdd9\xcf\xfb>\xcf\xf3{\xfe\xfc" +
-	"~\xef\xea\x1f\xd9\x10[\x93\xfc.I$6&S\xc1" +
-	"\xe3\xf5\x0b\xa7\xff\xff\xe6\xf9\xa3\xa4\xe7Xp\xe8\xcch" +
-	"\xf6\x8e\x7f\xe4[\"\xac\xbd\xc4\x0e\xc2\xb8\xca4\"c" +
-	"\x9am%\x04\x17V\x9e\xf9\xe4\xc4G\xaf\xbcEb)" +
-	"@\x94\xd0\x88\xd6\xdee\xbf\x81`\xe8n\x9d$\xb9:\xea\xe7\xd7" +
-	"\x94\xeb0\xff\x80\x10,\xba1\xd2m\xdf\xba\x89\xa1\x9b" +
-	"\x10L:\x9eo\x9buID\xe8\"\x86.\xc2a\xa7" +
-	"\xe1[\x8e\xed\xa1\xa7C\x07\x02zb-\xf8\x93\x01\x0f" +
-	"7\xfdIi\xfbV\xd9T\xceD\xe1l;\x90\x17\x13" +
-	"\x89!\x0e1\x16\x83\\\xf8_\xac\x8e\x08\xf2\x96\xbd\x9d" +
-	":\xb4\xe7\xe4\x81\x08U\xaf\xac\x9bV-\xfa\x8b\x8a\x19" +
-	"&\xed\x99\xce\x9d\x07\xe1\x9b\x08\xbb\xea\x86\xe8\xb66z" +
-	"\xc3\x0a\x15\xc6\xbe6\xc6\x1b\xaa\x83\xd79\xc4\xaf1\x8c" +
-	"\xb7U\x07\x7f\xe6\x10\xbf\xc70\xde\xc9\x11\x89[\x1c\x13" +
-	"`\x00\xcf\x82\x13\xe9w\xdf#\x9a\x00G\xa9\x0b\x0cz" +
-	"\x82g\x91 2\xe6a\x94\xa8\x94V\xf6\xac\xb2'\x13" +
-	"Y$\x15\xb7\xb0\x82\xa8\xd4\xa5\xec\xcb\x94=\xc5\xb2H" +
-	"\x11\x19K0ET\xeaS\xf6\xd5\xca\xae%\xb3\x8a\x96" +
-	"F?\\\xa2\xd2Je_\xaf\xec\xe9\x85Y\xa4\x89\x8c" +
-	"\x81\xd0\xbeN\xd9\x87\xc0\x10\x94k\x96\xb4\xfdB%>" +
-	"\xce\xfd\xd2\xf5,\xc7\x8e\xfe\xb9\xe3\xb5\xfb%gY\x89" +
-	"\xd6\xae\x15\x9d\x8c\xa2%2\x1d\xe9& C\x08\x1a\x8e" +
-	"S\x1b\xbfwM2\xbeY\xf50\x9fP\xe4@OG" +
-	"\x0a\x09\xca\x18\x84\xa4-\xfb\x16e\x1c\xbbPA\x8a\x18" +
-	"R\xed\xb9\x8d9\xd4[6k\x85F\x1b\x89\xe5\x0d7" +
-	"}\xa7\xd9\xa0\xde\x8a\xe9\xcb\x0a@\x0c\x88M\x94\xcd\x9d" +
-	"hocp\x9bYU\x13L\xb7'\xb8|\x05\x91\xe8" +
-	"\xe3\x10\xabc\x13\xecW[\xb6\x8cC\xacc\xc8\xa8U" +
-	"oo\xd4~\xb3\xd6\x94\xf7\xed\xce\xc34\xa5*\xfd\xd6" +
-	"W\xc1\xde\xe7\xf4\x15MW3\xeb\xde?\xf4\x9e\x90^" +
-	"FIC\\\x8f\x06\x89D\x9aCd\x19\xf2n\xa8\x1c" +
-	"\xe8\xe9H\xf6\x1c\"\xf2\xbfJ\x97oei\xb10I" +
-	"\xd4~'\x11=\x0f\xba8HL/h\xe8\xa0\x81\xb5\x9ffDO\xb0\xbe" +
-	"\xfc\x181}\x89\x16D:E\xf9V\xca!\x04Qu" +
-	"\xd4\x1b\xd67\x84 \x12CDzF4\x84\"\x1e\xbd" +
-	"\xdd\xf7ii\xaf\xf7(\x1d\x8b\xde\xad\x87\xf7\xab\x95'" +
-	"\xa3\xf0\xaan\xc5\xe2N\x11\x89.\x0e\xb1\x90!\xa89" +
-	"\xb3\xc2\x96\x19\x8f\xad\xd0\x83\x04\xa7\x058\x92\x9d\x8cr" +
-	"V\xf1{\xda\xf1M\xa5\x89\xbb9\xc4dl[\xa52" +
-	"\xee\xe1\x10\xb5\x98\xdeXJ\x99&9\xc4\xd1\x8e\xde\xbc" +
-	"|\x8cH\x1c\xe5\x10'\x184\xe9\xba\x11$\xad\xe9v" +
-	"T\xb2\xe6T\xc7,[z\x8a\xb6\xb3LUG\x8a\x9f" +
-	"\x0d\xe9\xd6M[\xda\xf07\x9bV\xad\xe9J\xb5Z-" +
-	"\xd2\xfd\x11\x00\x00\xff\xffy%\x9bh"
+const schema_db8274f9144abc7e = "x\xda\x9cU_l\x14U\x17\xff\x9d{w;\xdb\xa4" +
+	"e;\x99m\x02\x1bH\x13\xd2\x86B\xbe\xf2\xc1\xc7\x87" +
+	"B\xfd\xd3?\x02\xba\xb5\x94\xbdl1\x08}`\xd8\xbd" +
+	"l\xa7\xce\xcelffQH\x04%\x18#\x89\x04E" +
+	"^0\x9a@\xe2\x8b\x0fj\xe2\x83\x89\xc1\x04_\xe4\x81" +
+	"\x07^\xd4h$1J\x88\x91h\x88\x8d\x9ahb\xc6" +
+	"\xdc\xd9\xce\xecR\x14\xd0\xb7\x99\xdf=\xf7\x9c\xdf9\xf7" +
+	"\x9c\xdfY\xf7+\x1be\xeb\xd3_\xa7\x01\xb1%\xdd\x11" +
+	">X\xbbr\xfe\xbe3\x97\x8fC\xcf\xb3\xf0\xc8\x85\x89" +
+	"\xdco\xc1\xb1\xaf\x00\xda\xf0\x19;L\xc6\xf7L\x03\x8c" +
+	"\xebl\x07(\xbc\xf2\x9f\x0b\x1f\x9ez\xff\xc5\xd7!V" +
+	"\x11\x01)\x0d\xd8\xf0\x07\xfb\x9d@\x86\xceG@\xe1k" +
+	"_|4U{\xe5\xecy\xe8\xab\xe2\xf3\xcd\x9c1\xa4" +
+	"\xc2\xde\x02]\xbd\xb8>\xf5A\xf3$\xcd\xd5\xd1\x10\xbf" +
+	"\xa1\xae\x8e\xf1wA\xe1\x8a\x1f\xc7\xbb\x9d\x9b\xc7.B" +
+	"\xcfS\x8bE\xd3\xf0\x1b>A\xc6/\xea\xd3\xf8)2" +
+	"\x9e\xd8{\xfa\xd5\xf4\xf5\xd3\x97 \xf2\xd4n\xdd\xa1\xac" +
+	"_Nyd\x9c\x8b\x82\xbf\x91\xba\x9f\x81\xc2\xfc{\x0f" +
+	"\xbc3^\xf9\xf2\xf2\"\xdfQf\x9d\xda\xbc\xd1\xab\xa9" +
+	"/]{\x1a\x14\xb2\xeb\xe6\xb2\xe7>\x7f\xf8j[\x0a" +
+	"5\xed[B*\x9czb\xef\\\xe7\xb3\xd7\xae-\xa4" +
+	"@\xea\xc8\xd4\xa2\x14\x1a\x9a\xca~\xe3\xbe19\xb3i" +
+	"\xf7\x0d\xe8y~K!\xcfh\xc3d\xbc\x15\x059\xa7" +
+	"]2Vg4 \xa0\x85\xb1\xc8a\xa4\x19r" +
+	"\x94\xc28;\xf4E\xf9\x8dR\x18+)\xc5b\x08\x8c" +
+	"R\x91\xee\xbd\xdc\xb7\x09q\x9f\x7f/\x15\x8b\x97\xde\xdd" +
+	"\xeb\xd5\x8c\x93U|U\xb5\xda\xfc\xce\x01\xa2\x8b\x93X" +
+	"\xca(\xb4\xdd\x05U\xccN\xb5\xb5\xd0\x9d\xd4\xaaI8" +
+	"\xd6\xac\xac\xba\xac\xfc\xf7$\xfeM%\xa83\x9c\xc4l" +
+	"[\xb7J\x05\xee\xe3$\xec6A\xb5\xd4b\x98\xe5$" +
+	"\x8e'\x1a\xa5?\x7f\x02\x10\xc79\x89S\x8c4\xe9y" +
+	"1%\xad\xe1\xb5$\xd6v\xab\x93\x96#}5\xd0\x0b" +
+	"3\xac\x8e\xd4\xe4\xd6\xa5W3\x1d\xe9P\xb0\xcd\xb4\xec" +
+	"\x86'\x91\x0c\xdd\x9f\x01\x00\x00\xff\xffR3\x9d#"
 
 func init() {
 	schemas.Register(schema_db8274f9144abc7e,