-
Notifications
You must be signed in to change notification settings - Fork 544
Expand file tree
/
Copy pathroot.go
More file actions
202 lines (171 loc) · 5.67 KB
/
root.go
File metadata and controls
202 lines (171 loc) · 5.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
package cmd
import (
"fmt"
"os"
"time"
"github.com/google/uuid"
"github.com/rs/zerolog"
"github.com/cloudquery/cloudquery/cli/internal/enum"
"github.com/cloudquery/cloudquery/cli/internal/env"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/thoas/go-funk"
)
const sentryDsnDefault = "https://3d2f1b94bdb64884ab1a52f56ce56652@o1396617.ingest.sentry.io/6720193"
var (
Version = "development"
rootShort = "CloudQuery CLI"
rootLong = `CloudQuery CLI
Open source data integration at scale.
Find more information at:
https://www.cloudquery.io`
disableSentry = false
analyticsClient *AnalyticsClient
logFile *os.File
invocationUUID uuid.UUID
)
func NewCmdRoot() *cobra.Command {
logLevel := enum.NewEnum([]string{"trace", "debug", "info", "warn", "error"}, "info")
logFormat := enum.NewEnum([]string{"text", "json"}, "text")
telemetryLevel := enum.NewEnum([]string{"none", "errors", "stats", "all"}, "all")
logConsole := false
noLogFile := false
logFileName := "cloudquery.log"
sentryDsn := sentryDsnDefault
// support legacy telemetry environment variable,
// but the newer CQ_TELEMETRY_LEVEL environment variable takes precedence
defaultTelemetryValue := telemetryLevel.Value
legacyTelemetry := os.Getenv("CQ_NO_TELEMETRY")
if legacyTelemetry != "" {
defaultTelemetryValue = "none"
}
err := telemetryLevel.Set(env.GetEnvOrDefault("CQ_TELEMETRY_LEVEL", defaultTelemetryValue))
if err != nil {
fmt.Fprintf(os.Stderr, "failed to set telemetry level: "+err.Error())
os.Exit(1)
}
cmd := &cobra.Command{
Use: "cloudquery",
Short: rootShort,
Long: rootLong,
Version: Version,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
zerolog.TimestampFunc = func() time.Time {
return time.Now().UTC()
}
// Don't print usage on command errors.
// PersistentPreRunE runs after argument parsing, so errors during parsing will result in printing the help
cmd.SilenceUsage = true
var err error
invocationUUID, err = uuid.NewRandom()
if err != nil {
return fmt.Errorf("failed to generate invocation uuid: %w", err)
}
if logFile, err = initLogging(noLogFile, logLevel, logFormat, logConsole, logFileName); err != nil {
return err
}
// log warnings now that the logger is initialized
if legacyTelemetry != "" {
log.Warn().Msg("The CQ_NO_TELEMETRY environment variable will be deprecated, please use CQ_TELEMETRY_LEVEL=none instead.")
}
sendStats := funk.ContainsString([]string{"all", "stats"}, telemetryLevel.String())
customAnalyticsHost := os.Getenv("CQ_ANALYTICS_HOST") != defaultAnalyticsHost
if (Version != "development" || customAnalyticsHost) && sendStats {
analyticsClient, err = initAnalytics()
if err != nil {
log.Warn().Err(err).Msg("failed to initialize analytics client")
}
}
sendErrors := funk.ContainsString([]string{"all", "errors"}, telemetryLevel.String())
if sentryDsn != "" && Version != "development" && sendErrors {
if err := initSentry(sentryDsn, Version); err != nil {
// we don't fail on sentry init errors as there might be no connection or sentry can be blocked.
log.Warn().Err(err).Msg("failed to initialize sentry")
}
} else {
disableSentry = true
}
return nil
},
}
cmd.PersistentFlags().String("cq-dir", ".cq", "directory to store cloudquery files, such as downloaded plugins")
cmd.PersistentFlags().String("data-dir", "", "set persistent data directory")
err = cmd.PersistentFlags().MarkDeprecated("data-dir", "use cq-dir instead")
if err != nil {
panic(err)
}
cmd.PersistentFlags().String("color", "auto", "Enable colorized output when log-console is set (on, off, auto)")
err = cmd.PersistentFlags().MarkDeprecated("color", "console logs are always colorless")
if err != nil {
panic(err)
}
// Logging Flags
cmd.PersistentFlags().BoolVar(&logConsole, "log-console", false, "enable console logging")
cmd.PersistentFlags().Var(logFormat, "log-format", "Logging format (json, text)")
cmd.PersistentFlags().Var(logLevel, "log-level", "Logging level (trace, debug, info, warn, error)")
cmd.PersistentFlags().BoolVar(&noLogFile, "no-log-file", false, "Disable logging to file")
cmd.PersistentFlags().StringVar(&logFileName, "log-file-name", "cloudquery.log", "Log filename")
// Telemetry (analytics) flags
f := cmd.PersistentFlags().VarPF(telemetryLevel, "telemetry-level", "", "Telemetry level (none, errors, stats, all)")
f.DefValue = "all"
cmd.SetHelpCommand(&cobra.Command{Hidden: true})
pluginCmd := &cobra.Command{
Use: "plugin",
Short: "Plugin commands",
}
pluginDocCmd := &cobra.Command{
Use: "docs",
Short: "Plugin docs commands",
Hidden: true,
}
pluginDocCmd.AddCommand(
newCmdPluginDocsDownload(),
newCmdPluginDocsUpload(),
)
pluginCmd.AddCommand(
newCmdPluginInstall(false),
newCmdPluginPublish(),
pluginDocCmd,
)
addonCmd := &cobra.Command{
Use: "addon",
Short: "Addon commands",
}
addonCmd.AddCommand(
newCmdAddonDownload(),
newCmdAddonPublish(),
)
cmd.AddCommand(
NewCmdSync(),
NewCmdMigrate(),
newCmdDoc(),
NewCmdTables(),
newCmdLogin(),
newCmdLogout(),
newCmdSwitch(),
newCmdPluginInstall(true), // legacy
pluginCmd,
addonCmd,
)
cmd.CompletionOptions.HiddenDefaultCmd = true
cmd.DisableAutoGenTag = true
cobra.OnFinalize(func() {
if analyticsClient != nil {
analyticsClient.Close()
}
})
return cmd
}
// formats a timestamp in UTC and RFC3339
func formatTimestampUtcRfc3339(timestamp any) string {
timestampConcrete, ok := timestamp.(time.Time)
if !ok {
return fmt.Sprintf("%v", timestamp)
}
return timestampConcrete.UTC().Format(time.RFC3339)
}
func CloseLogFile() {
if logFile != nil {
logFile.Close()
}
}