Use an enum for TD severity

Change-Id: I8ff9f6f066966a7af38e6641dfa8dfe409a16571
Reviewed-on: https://skia-review.googlesource.com/c/buildbot/+/253018
Commit-Queue: Eric Boren <borenet@google.com>
Auto-Submit: Ben Wagner aka dogben <benjaminwagner@google.com>
Reviewed-by: Eric Boren <borenet@google.com>
diff --git a/task_driver/examples/file_stream/file_stream.go b/task_driver/examples/file_stream/file_stream.go
index d1ff805..d4fb6f5 100644
--- a/task_driver/examples/file_stream/file_stream.go
+++ b/task_driver/examples/file_stream/file_stream.go
@@ -18,7 +18,6 @@
 	"runtime"
 
 	"go.skia.org/infra/go/exec"
-	"go.skia.org/infra/go/sklog"
 	"go.skia.org/infra/go/util"
 	"go.skia.org/infra/task_driver/go/td"
 )
@@ -59,7 +58,7 @@
 		return td.FailStep(ctx, fmt.Errorf("Failed to obtain path of current file."))
 	}
 	script := filepath.Join(filepath.Dir(filename), "write_logs.py")
-	fs, err := td.NewFileStream(ctx, "verbose", sklog.DEBUG)
+	fs, err := td.NewFileStream(ctx, "verbose", td.Debug)
 	if err != nil {
 		return td.FailStep(ctx, err)
 	}
@@ -84,7 +83,7 @@
 	}); err != nil {
 		return td.FailStep(ctx, err)
 	}
-	fs, err := td.NewFileStream(ctx, "copied", sklog.DEBUG)
+	fs, err := td.NewFileStream(ctx, "copied", td.Debug)
 	if err != nil {
 		return td.FailStep(ctx, err)
 	}
diff --git a/task_driver/go/lib/docker/docker.go b/task_driver/go/lib/docker/docker.go
index 088ea94..181dd89 100644
--- a/task_driver/go/lib/docker/docker.go
+++ b/task_driver/go/lib/docker/docker.go
@@ -63,7 +63,7 @@
 	if err := cmd.Start(); err != nil {
 		return td.FailStep(ctx, err)
 	}
-	logStream := td.NewLogStream(ctx, "docker", "Info")
+	logStream := td.NewLogStream(ctx, "docker", td.Info)
 	scanner := bufio.NewScanner(stdOut)
 
 	// Spin up a Go routine to parse the step output of the Docker build and
@@ -87,7 +87,7 @@
 					td.EndStep(subStepContext)
 				}
 				subStepContext = td.StartStep(ctx, td.Props(line))
-				logStream = td.NewLogStream(subStepContext, line, "Info")
+				logStream = td.NewLogStream(subStepContext, line, td.Info)
 			} else {
 				// Otherwise just write the log line to the current logStream.
 				if _, err := logStream.Write([]byte(line)); err != nil {
diff --git a/task_driver/go/td/receiver.go b/task_driver/go/td/receiver.go
index 5734b19..fe1688c 100644
--- a/task_driver/go/td/receiver.go
+++ b/task_driver/go/td/receiver.go
@@ -15,12 +15,34 @@
 	"go.skia.org/infra/go/util"
 )
 
+// Severity indicates the importance of a LogStream, with greater values
+// indicating greater severity. Valid values include Debug, Info, Warning, and
+// Error.
+type Severity int
+
+const (
+	Debug   = Severity(logging.Debug)
+	Info    = Severity(logging.Info)
+	Warning = Severity(logging.Warning)
+	Error   = Severity(logging.Error)
+)
+
+// asCloudLoggingSeverity returns the equivalent logging.Severity for s.
+func (s Severity) asCloudLoggingSeverity() logging.Severity {
+	return logging.Severity(s)
+}
+
+// String returns the name of s.
+func (s Severity) String() string {
+	return s.asCloudLoggingSeverity().String()
+}
+
 // Receiver is an interface used to implement arbitrary receivers of step
 // metadata, as steps are run.
 type Receiver interface {
 	// Handle the given message.
 	HandleMessage(*Message) error
-	LogStream(stepId string, logId string, severity string) (io.Writer, error)
+	LogStream(stepId string, logId string, severity Severity) (io.Writer, error)
 	Close() error
 }
 
@@ -41,7 +63,7 @@
 }
 
 // See documentation for Receiver interface.
-func (r MultiReceiver) LogStream(stepId, logId, severity string) (io.Writer, error) {
+func (r MultiReceiver) LogStream(stepId, logId string, severity Severity) (io.Writer, error) {
 	writers := make([]io.Writer, 0, len(r))
 	for _, rec := range r {
 		w, err := rec.LogStream(stepId, logId, severity)
@@ -96,9 +118,8 @@
 }
 
 // See documentation for Receiver interface.
-func (r *DebugReceiver) LogStream(stepId, logId, severity string) (io.Writer, error) {
-	sev := logging.ParseSeverity(severity)
-	if sev >= logging.Warning {
+func (r *DebugReceiver) LogStream(stepId, logId string, severity Severity) (io.Writer, error) {
+	if severity >= Warning {
 		return os.Stderr, nil
 	}
 	return os.Stdout, nil
@@ -269,7 +290,7 @@
 }
 
 // See documentation for Receiver interface.
-func (r *ReportReceiver) LogStream(stepId, logId, severity string) (io.Writer, error) {
+func (r *ReportReceiver) LogStream(stepId, logId string, _ Severity) (io.Writer, error) {
 	r.mtx.Lock()
 	defer r.mtx.Unlock()
 
@@ -337,14 +358,14 @@
 }
 
 // See documentation for Receiver interface.
-func (r *CloudLoggingReceiver) LogStream(stepId, logId, severity string) (io.Writer, error) {
+func (r *CloudLoggingReceiver) LogStream(stepId, logId string, severity Severity) (io.Writer, error) {
 	return &cloudLogsWriter{
 		logger: r.logger,
 		labels: map[string]string{
 			"logId":  logId,
 			"stepId": stepId,
 		},
-		severity: logging.ParseSeverity(severity),
+		severity: severity.asCloudLoggingSeverity(),
 	}, nil
 }
 
diff --git a/task_driver/go/td/run.go b/task_driver/go/td/run.go
index c238e4c..3cabc0e 100644
--- a/task_driver/go/td/run.go
+++ b/task_driver/go/td/run.go
@@ -342,7 +342,7 @@
 }
 
 // Open a log stream.
-func (r *run) LogStream(stepId, logName, severity string) io.Writer {
+func (r *run) LogStream(stepId, logName string, severity Severity) io.Writer {
 	logId := uuid.New().String() // TODO(borenet): Come up with a better ID.
 	w, err := r.receiver.LogStream(stepId, logId, severity)
 	if err != nil {
@@ -358,7 +358,7 @@
 			r.AddStepData(stepId, DATA_TYPE_LOG, &LogData{
 				Name:     logName,
 				Id:       logId,
-				Severity: severity,
+				Severity: severity.String(),
 			})
 		},
 	}
diff --git a/task_driver/go/td/step.go b/task_driver/go/td/step.go
index e62a02b..0903692 100644
--- a/task_driver/go/td/step.go
+++ b/task_driver/go/td/step.go
@@ -230,7 +230,7 @@
 
 // Create an io.Writer that will act as a log stream for this Step. Callers
 // probably want to use a higher-level method instead.
-func NewLogStream(ctx context.Context, name, severity string) io.Writer {
+func NewLogStream(ctx context.Context, name string, severity Severity) io.Writer {
 	props := getCtx(ctx).step
 	return getCtx(ctx).run.LogStream(props.Id, name, severity)
 }
@@ -255,7 +255,7 @@
 
 // Create a log stream which uses an intermediate file, eg. for writing from a
 // test program.
-func NewFileStream(ctx context.Context, name, severity string) (*FileStream, error) {
+func NewFileStream(ctx context.Context, name string, severity Severity) (*FileStream, error) {
 	w := NewLogStream(ctx, name, severity)
 	f, err := ioutil.TempFile("", "log")
 	if err != nil {
@@ -379,12 +379,12 @@
 
 		return Do(ctx, Props(name).Env(cmd.Env), func(ctx context.Context) error {
 			// Set up stdout and stderr streams.
-			stdout := NewLogStream(ctx, "stdout", sklog.INFO)
+			stdout := NewLogStream(ctx, "stdout", Info)
 			if cmd.Stdout != nil {
 				stdout = util.MultiWriter([]io.Writer{cmd.Stdout, stdout})
 			}
 			cmd.Stdout = stdout
-			stderr := NewLogStream(ctx, "stderr", sklog.ERROR)
+			stderr := NewLogStream(ctx, "stderr", Error)
 			if cmd.Stderr != nil {
 				stderr = util.MultiWriter([]io.Writer{cmd.Stderr, stderr})
 			}