2017-11-09 21:38:03 +01:00
|
|
|
// Copyright 2016-2017, Pulumi Corporation. All rights reserved.
|
|
|
|
|
|
|
|
package cmd
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2017-11-21 01:37:41 +01:00
|
|
|
"regexp"
|
|
|
|
"strconv"
|
2017-11-09 21:38:03 +01:00
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
|
2017-11-20 07:28:49 +01:00
|
|
|
"github.com/pulumi/pulumi/pkg/operations"
|
2017-11-09 21:38:03 +01:00
|
|
|
"github.com/pulumi/pulumi/pkg/util/cmdutil"
|
|
|
|
)
|
|
|
|
|
|
|
|
func newLogsCmd() *cobra.Command {
|
|
|
|
var stack string
|
|
|
|
var follow bool
|
2017-11-21 01:37:41 +01:00
|
|
|
var since string
|
2017-11-09 21:38:03 +01:00
|
|
|
|
|
|
|
logsCmd := &cobra.Command{
|
2017-11-14 22:28:27 +01:00
|
|
|
Use: "logs",
|
|
|
|
Short: "Show aggregated logs for a project",
|
2017-11-09 21:38:03 +01:00
|
|
|
Run: cmdutil.RunFunc(func(cmd *cobra.Command, args []string) error {
|
|
|
|
stackName, err := explicitOrCurrent(stack, backend)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-11-21 01:37:41 +01:00
|
|
|
startTime := parseRelativeDuration(since)
|
|
|
|
|
2017-11-09 21:38:03 +01:00
|
|
|
sinceTime := time.Unix(0, 0)
|
|
|
|
highestTimeSeen := time.Unix(0, 0)
|
|
|
|
|
|
|
|
for {
|
2017-11-21 01:37:41 +01:00
|
|
|
logs, err := backend.GetLogs(stackName, operations.LogQuery{
|
|
|
|
StartTime: startTime,
|
|
|
|
})
|
2017-11-09 21:38:03 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, logEntry := range logs {
|
|
|
|
eventTime := time.Unix(0, logEntry.Timestamp*1000000)
|
|
|
|
if eventTime.After(sinceTime) {
|
2017-11-20 23:55:09 +01:00
|
|
|
fmt.Printf("%29v[%25v] %v\n", eventTime.Format(time.RFC3339Nano), logEntry.ID, logEntry.Message)
|
2017-11-09 21:38:03 +01:00
|
|
|
}
|
|
|
|
if eventTime.After(highestTimeSeen) {
|
|
|
|
highestTimeSeen = eventTime
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !follow {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
sinceTime = highestTimeSeen
|
|
|
|
time.Sleep(time.Second)
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
|
|
|
logsCmd.PersistentFlags().StringVarP(
|
|
|
|
&stack, "stack", "s", "",
|
|
|
|
"List configuration for a different stack than the currently selected stack")
|
|
|
|
logsCmd.PersistentFlags().BoolVarP(
|
|
|
|
&follow, "follow", "f", false,
|
|
|
|
"Follow the log stream in real time (like tail -f)")
|
2017-11-21 01:37:41 +01:00
|
|
|
logsCmd.PersistentFlags().StringVar(
|
|
|
|
&since, "since", "",
|
|
|
|
"Only return logs newer than a relative duration ('5s', '2m', '3h'). Defaults to returning all logs.")
|
2017-11-09 21:38:03 +01:00
|
|
|
|
|
|
|
return logsCmd
|
|
|
|
}
|
2017-11-21 01:37:41 +01:00
|
|
|
|
|
|
|
var durationRegexp = regexp.MustCompile(`(\d+)([y|w|d|h|m|s])`)
|
|
|
|
|
|
|
|
// parseRelativeDuration extracts a time.Time previous to now by the a relative duration in the format '5s', '2m', '3h'.
|
|
|
|
func parseRelativeDuration(duration string) *time.Time {
|
|
|
|
now := time.Now()
|
|
|
|
if duration == "" {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
parts := durationRegexp.FindStringSubmatch(duration)
|
|
|
|
if parts == nil {
|
|
|
|
fmt.Printf("Err: %v\n", duration)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
num, err := strconv.ParseInt(parts[1], 10, 64)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("Err: %v\n", err)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
d := time.Duration(-num)
|
|
|
|
switch parts[2] {
|
|
|
|
case "y":
|
|
|
|
d *= time.Hour * 24 * 365
|
|
|
|
case "w":
|
|
|
|
d *= time.Hour * 24 * 7
|
|
|
|
case "d":
|
|
|
|
d *= time.Hour * 24
|
|
|
|
case "h":
|
|
|
|
d *= time.Hour
|
|
|
|
case "m":
|
|
|
|
d *= time.Minute
|
|
|
|
case "s":
|
|
|
|
d *= time.Second
|
|
|
|
default:
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
// fmt.Printf("Duration: %v\n", d)
|
|
|
|
ret := now.Add(d)
|
|
|
|
fmt.Printf("Since: %v\n", ret.Format(time.RFC3339Nano))
|
|
|
|
return &ret
|
|
|
|
}
|