From c625a5db1a63565e356fad7aa31b4e54ba081f60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristhian=20Fern=C3=A1ndez?= Date: Fri, 26 Jan 2024 14:12:42 -0500 Subject: [PATCH] feat: logs (#2069) --- cmd/logs.go | 47 ++++++++++++++++++ go.mod | 18 +++---- go.sum | 21 ++------ internal/cluster/cluster.go | 2 +- internal/common/common.go | 1 + internal/launch/cmd.go | 4 +- internal/launch/constants.go | 2 +- internal/provisionLogs/command.go | 64 +++++++++++++++++++++++++ internal/provisionLogs/constants.go | 29 +++++++++++ internal/provisionLogs/message.go | 31 ++++++++++++ internal/provisionLogs/provisionLogs.go | 57 ++++++++++++++++++++++ internal/provisionLogs/types.go | 17 +++++++ internal/utilities/utilities.go | 36 ++++++++++++++ main.go | 51 +++++++++++++++----- 14 files changed, 337 insertions(+), 43 deletions(-) create mode 100755 cmd/logs.go create mode 100644 internal/provisionLogs/command.go create mode 100644 internal/provisionLogs/constants.go create mode 100644 internal/provisionLogs/message.go create mode 100644 internal/provisionLogs/provisionLogs.go create mode 100644 internal/provisionLogs/types.go diff --git a/cmd/logs.go b/cmd/logs.go new file mode 100755 index 000000000..34eb311e7 --- /dev/null +++ b/cmd/logs.go @@ -0,0 +1,47 @@ +/* +Copyright (C) 2021-2023, Kubefirst + +This program is licensed under MIT. +See the LICENSE file for more details. +*/ +package cmd + +import ( + "fmt" + "os" + + "github.com/kubefirst/kubefirst/internal/provisionLogs" + "github.com/nxadm/tail" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +// infoCmd represents the info command +var logsCmd = &cobra.Command{ + Use: "logs", + Short: "kubefirst real time logs", + Long: `kubefirst real time logs`, + RunE: func(cmd *cobra.Command, args []string) error { + provisionLogs.InitializeProvisionLogsTerminal() + + go func() { + t, err := tail.TailFile(viper.GetString("k1-paths.log-file"), tail.Config{Follow: true, ReOpen: true}) + if err != nil { + fmt.Printf("Error tailing log file: %v\n", err) + os.Exit(1) + } + + for line := range t.Lines { + provisionLogs.AddLog(line.Text) + } + }() + + provisionLogs.ProvisionLogs.Run() + + return nil + }, +} + +func init() { + rootCmd.AddCommand(logsCmd) +} diff --git a/go.mod b/go.mod index 6090f22ec..c9075914f 100644 --- a/go.mod +++ b/go.mod @@ -14,11 +14,11 @@ require ( github.com/dustin/go-humanize v1.0.1 github.com/go-git/go-git/v5 v5.6.1 github.com/hashicorp/vault/api v1.9.0 - github.com/kubefirst/kubefirst-api v0.1.8 + github.com/kubefirst/kubefirst-api v0.1.9 github.com/kubefirst/metrics-client v0.3.0 - github.com/kubefirst/runtime v0.3.35 + github.com/kubefirst/runtime v0.3.37 + github.com/nxadm/tail v1.4.8 github.com/rs/zerolog v1.29.1 - github.com/segmentio/analytics-go v3.1.0+incompatible github.com/sirupsen/logrus v1.9.0 github.com/spf13/cobra v1.7.0 github.com/spf13/viper v1.15.0 @@ -107,7 +107,6 @@ require ( github.com/gofrs/flock v0.7.0 // indirect github.com/golang-jwt/jwt/v4 v4.4.3 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/snappy v0.0.4 // indirect github.com/google/btree v1.0.1 // indirect github.com/google/gnostic v0.6.9 // indirect github.com/google/go-github/v45 v45.2.0 // indirect @@ -137,7 +136,6 @@ require ( github.com/moby/spdystream v0.2.0 // indirect github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect - github.com/montanaflynn/stats v0.6.6 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect @@ -156,6 +154,7 @@ require ( github.com/rs/xid v1.4.0 // indirect github.com/russross/blackfriday v1.6.0 // indirect github.com/sahilm/fuzzy v0.1.0 // indirect + github.com/segmentio/analytics-go v3.1.0+incompatible // indirect github.com/segmentio/backo-go v1.0.1 // indirect github.com/skeema/knownhosts v1.1.0 // indirect github.com/vmihailenco/go-tinylfu v0.2.1 // indirect @@ -163,12 +162,8 @@ require ( github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/vultr/govultr/v3 v3.0.2 // indirect github.com/xanzy/go-gitlab v0.81.0 // indirect - github.com/xdg-go/pbkdf2 v1.0.0 // indirect - github.com/xdg-go/scram v1.1.1 // indirect - github.com/xdg-go/stringprep v1.0.3 // indirect github.com/xlab/treeprint v1.1.0 // indirect github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect - github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect github.com/yuin/goldmark v1.5.2 // indirect github.com/yuin/goldmark-emoji v1.0.1 // indirect go.opencensus.io v0.24.0 // indirect @@ -183,6 +178,7 @@ require ( google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect google.golang.org/grpc v1.55.0 // indirect + gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect k8s.io/apiextensions-apiserver v0.26.0 // indirect k8s.io/apiserver v0.26.2 // indirect k8s.io/cli-runtime v0.24.2 // indirect @@ -256,7 +252,7 @@ require ( github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b // indirect github.com/muesli/cancelreader v0.2.2 // indirect github.com/muesli/reflow v0.3.0 // indirect - github.com/muesli/termenv v0.15.2 // indirect + github.com/muesli/termenv v0.15.2 github.com/pelletier/go-toml/v2 v2.0.6 // indirect github.com/rivo/uniseg v0.4.2 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect @@ -270,7 +266,7 @@ require ( golang.org/x/net v0.14.0 // indirect golang.org/x/oauth2 v0.8.0 // indirect golang.org/x/sys v0.11.0 // indirect - golang.org/x/term v0.11.0 + golang.org/x/term v0.11.0 // indirect golang.org/x/text v0.12.0 // indirect golang.org/x/time v0.3.0 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/go.sum b/go.sum index b0f98e3ec..3c21219db 100644 --- a/go.sum +++ b/go.sum @@ -504,8 +504,6 @@ github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0 github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -721,14 +719,12 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kubefirst/kubefirst-api v0.1.8 h1:+5AT9pDj4AuH2GCW43Z9U/frEEyemqeZOm3zKGHd6no= -github.com/kubefirst/kubefirst-api v0.1.8/go.mod h1:Euz7+acib+o9DTkJ3MXRVtPL1rI+vGFZditYG2aXQCY= -github.com/kubefirst/metrics-client v0.2.8 h1:JfaeiBifZD/DpyYW2QVHcrhH/KWA98OmM+7c7M12qMc= -github.com/kubefirst/metrics-client v0.2.8/go.mod h1:GR7wsMcyYhd+EU67PeuMCBYFE6OJ7P/j5OI5BLOoRMc= +github.com/kubefirst/kubefirst-api v0.1.9 h1:HCPO2usOW64NS3B/zRL84qfADBNFfcbeKd3yWdbvf8I= +github.com/kubefirst/kubefirst-api v0.1.9/go.mod h1:hik4k99JDLrxxh25jYt6eYxYPhIodX1yxb4gh5tfJ3U= github.com/kubefirst/metrics-client v0.3.0 h1:zCug82pEzeWhHhpeYQvdhytRNDxrLxX18dPQ5PSxY3s= github.com/kubefirst/metrics-client v0.3.0/go.mod h1:GR7wsMcyYhd+EU67PeuMCBYFE6OJ7P/j5OI5BLOoRMc= -github.com/kubefirst/runtime v0.3.35 h1:wn430Irf0E1vc3X0WX3lYBpyhQ5TN6xxMcargILA9uI= -github.com/kubefirst/runtime v0.3.35/go.mod h1:0CnYy+8JTG+/0f3QlkTQJqTT654Su6JXk30OufFVY98= +github.com/kubefirst/runtime v0.3.37 h1:OaDcdlsRHMbgwu8T1/Z5etFtambEmlkZMW8WH/3J2z4= +github.com/kubefirst/runtime v0.3.37/go.mod h1:0CnYy+8JTG+/0f3QlkTQJqTT654Su6JXk30OufFVY98= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/libopenstorage/openstorage v1.0.0/go.mod h1:Sp1sIObHjat1BeXhfMqLZ14wnOzEhNx2YQedreMcUyc= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= @@ -828,8 +824,6 @@ github.com/mohae/deepcopy v0.0.0-20170603005431-491d3605edfb/go.mod h1:TaXosZuwd github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= -github.com/montanaflynn/stats v0.6.6 h1:Duep6KMIDpY4Yo11iFsvyqJDyfzLF9+sndUKT+v64GQ= -github.com/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= @@ -1109,7 +1103,6 @@ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69 github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= -github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= @@ -1135,11 +1128,8 @@ github.com/xanzy/go-gitlab v0.81.0 h1:ofbhZ5ZY9AjHATWQie4qd2JfncdUmvcSA/zfQB767D github.com/xanzy/go-gitlab v0.81.0/go.mod h1:VMbY3JIWdZ/ckvHbQqkyd3iYk2aViKrNIQ23IbFMQDo= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= -github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= -github.com/xdg-go/scram v1.1.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E= github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= -github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCOIs= github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= @@ -1151,8 +1141,6 @@ github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1: github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c h1:3lbZUMbMiGUW/LMkfsEABsc5zNT9+b1CvsJx47JzJ8g= github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c/go.mod h1:UrdRz5enIKZ63MEE3IF9l2/ebyx59GyGgPi+tICQdmM= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= -github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a h1:fZHgsYlfvtyqToslyjUt3VOPF4J7aK/3MPcK7xp3PDk= -github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/R083muKhosV54bj5niojjWZvU8xrevuH4= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -1232,7 +1220,6 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= diff --git a/internal/cluster/cluster.go b/internal/cluster/cluster.go index 0f6e5fff4..001214f21 100644 --- a/internal/cluster/cluster.go +++ b/internal/cluster/cluster.go @@ -65,7 +65,7 @@ func CreateCluster(cluster apiTypes.ClusterDefinition) error { return err } - if res.StatusCode != http.StatusOK { + if res.StatusCode != http.StatusAccepted { log.Info().Msgf("unable to create cluster %s %s", res.Status, body) return fmt.Errorf("unable to create cluster %s %s", res.Status, body) } diff --git a/internal/common/common.go b/internal/common/common.go index cbb53edb3..4edfd7c57 100644 --- a/internal/common/common.go +++ b/internal/common/common.go @@ -161,6 +161,7 @@ func Destroy(cmd *cobra.Command, args []string) error { viper.Set("launch", "") viper.Set("kubefirst", "") viper.Set("flags", "") + viper.Set("k1-paths", "") viper.WriteConfig() if _, err := os.Stat(config.K1Dir + "/kubeconfig"); !os.IsNotExist(err) { diff --git a/internal/launch/cmd.go b/internal/launch/cmd.go index 126922625..cf8b6dfa7 100644 --- a/internal/launch/cmd.go +++ b/internal/launch/cmd.go @@ -186,7 +186,7 @@ func Up(additionalHelmFlags []string, inCluster bool, useTelemetry bool) { log.Info().Msg("Creating k3d cluster for Kubefirst console and API...") err = k3d.ClusterCreateConsoleAPI( consoleClusterName, - kubeconfigPath, + fmt.Sprintf("%s/.k1", homeDir), k3dClient, fmt.Sprintf("%s/kubeconfig", dir), ) @@ -336,6 +336,8 @@ func Up(additionalHelmFlags []string, inCluster bool, useTelemetry bool) { fmt.Sprintf("global.kubefirstTeamInfo=%s", kubefirstTeamInfo), "--set", fmt.Sprintf("global.useTelemetry=%s", strconv.FormatBool(useTelemetry)), + "--set", + "kubefirst-api.includeVolume=true", } if len(additionalHelmFlags) > 0 { diff --git a/internal/launch/constants.go b/internal/launch/constants.go index b119f5cc8..f6fa66de4 100644 --- a/internal/launch/constants.go +++ b/internal/launch/constants.go @@ -11,7 +11,7 @@ const ( helmChartName = "kubefirst" helmChartRepoName = "kubefirst" helmChartRepoURL = "https://charts.kubefirst.com" - helmChartVersion = "2.3.8-rc16" + helmChartVersion = "2.3.8-rc44" namespace = "kubefirst" secretName = "kubefirst-initial-secrets" ) diff --git a/internal/provisionLogs/command.go b/internal/provisionLogs/command.go new file mode 100644 index 000000000..8e11009e6 --- /dev/null +++ b/internal/provisionLogs/command.go @@ -0,0 +1,64 @@ +/* +Copyright (C) 2021-2023, Kubefirst + +This program is licensed under MIT. +See the LICENSE file for more details. +*/ +package provisionLogs + +import ( + "encoding/json" + "fmt" + "strings" + "time" + + "github.com/muesli/termenv" +) + +type Log struct { + Level string `bson:"level" json:"level"` + Time string `bson:"time" json:"time"` + Message string `bson:"message" json:"message"` +} + +var ( + color = termenv.EnvColorProfile().Color + infoStyle = termenv.Style{}.Foreground(color("27")).Styled + errorStyle = termenv.Style{}.Foreground(color("196")).Styled + timeStyle = termenv.Style{}.Foreground(color("245")).Bold().Styled + textStyle = termenv.Style{}.Foreground(color("15")).Styled +) + +func AddLog(logMsg string) { + log := Log{} + formatterMsg := "" + + err := json.Unmarshal([]byte(logMsg), &log) + if err != nil { + formatterMsg = textStyle(logMsg) + } else { + parsedTime, err := time.Parse(time.RFC3339, log.Time) + if err != nil { + fmt.Println("Error parsing date:", err) + return + } + + // Format the parsed time into the desired format + formattedDateStr := parsedTime.Format("2006-01-02 15:04:05") + + timeLog := timeStyle(formattedDateStr) + level := infoStyle(strings.ToUpper(log.Level)) + + if log.Level == "error" { + level = errorStyle(strings.ToUpper(log.Level)) + } + + message := textStyle(log.Message) + + formatterMsg = fmt.Sprintf("%s %s: %s", timeLog, level, message) + } + + renderedMessage := formatterMsg + + ProvisionLogs.Send(logMessage{message: renderedMessage}) +} diff --git a/internal/provisionLogs/constants.go b/internal/provisionLogs/constants.go new file mode 100644 index 000000000..7a35585ba --- /dev/null +++ b/internal/provisionLogs/constants.go @@ -0,0 +1,29 @@ +/* +Copyright (C) 2021-2023, Kubefirst + +This program is licensed under MIT. +See the LICENSE file for more details. +*/ +package provisionLogs + +import ( + "time" + + "github.com/charmbracelet/lipgloss" +) + +const ( + padding = 2 + maxWidth = 80 +) + +const debounceDuration = time.Second * 10 + +var ( + currentPkgNameStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("211")) + doneStyle = lipgloss.NewStyle().Margin(1, 2) + checkMark = lipgloss.NewStyle().Foreground(lipgloss.Color("42")).SetString("✓") + helpStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#626262")).Render + StatusStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#FFFFFF")).Bold(true).Render + spinnerStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("69")) +) diff --git a/internal/provisionLogs/message.go b/internal/provisionLogs/message.go new file mode 100644 index 000000000..65ce7e5be --- /dev/null +++ b/internal/provisionLogs/message.go @@ -0,0 +1,31 @@ +/* +Copyright (C) 2021-2023, Kubefirst + +This program is licensed under MIT. +See the LICENSE file for more details. + +Emojis definition https://github.com/yuin/goldmark-emoji/blob/master/definition/github.go +Color definition https://www.ditig.com/256-colors-cheat-sheet +*/ +package provisionLogs + +import ( + "log" + + "github.com/charmbracelet/glamour" + "github.com/kubefirst/kubefirst/internal/progress" +) + +func renderMessage(message string) string { + r, _ := glamour.NewTermRenderer( + glamour.WithStyles(progress.StyleConfig), + glamour.WithEmoji(), + ) + + out, err := r.Render(message) + if err != nil { + log.Println(err.Error()) + return err.Error() + } + return out +} diff --git a/internal/provisionLogs/provisionLogs.go b/internal/provisionLogs/provisionLogs.go new file mode 100644 index 000000000..c3648b2b6 --- /dev/null +++ b/internal/provisionLogs/provisionLogs.go @@ -0,0 +1,57 @@ +/* +Copyright (C) 2021-2023, Kubefirst + +This program is licensed under MIT. +See the LICENSE file for more details. +*/ +package provisionLogs + +import ( + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" +) + +var quitStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("241")).Render + +var ProvisionLogs *tea.Program + +func NewModel() provisionLogsModel { + return provisionLogsModel{} +} + +// Bubbletea functions +func InitializeProvisionLogsTerminal() { + ProvisionLogs = tea.NewProgram(NewModel()) +} + +func (m provisionLogsModel) Init() tea.Cmd { + return nil +} + +func (m provisionLogsModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.KeyMsg: + switch msg.String() { + case "ctrl+c": + return m, tea.Quit + default: + return m, nil + } + + case logMessage: + m.logs = append(m.logs, msg.message) + return m, nil + + default: + return m, nil + } +} + +func (m provisionLogsModel) View() string { + logs := "" + for i := 0; i < len(m.logs); i++ { + logs = logs + m.logs[i] + "\n" + } + + return logs + "\n" + quitStyle("ctrl+c to quit") + "\n" +} diff --git a/internal/provisionLogs/types.go b/internal/provisionLogs/types.go new file mode 100644 index 000000000..e8a69e131 --- /dev/null +++ b/internal/provisionLogs/types.go @@ -0,0 +1,17 @@ +/* +Copyright (C) 2021-2023, Kubefirst + +This program is licensed under MIT. +See the LICENSE file for more details. +*/ +package provisionLogs + +// Terminal model +type provisionLogsModel struct { + logs []string +} + +// Bubbletea messsages +type logMessage struct { + message string +} diff --git a/internal/utilities/utilities.go b/internal/utilities/utilities.go index 238a99e4f..86b4ccbee 100644 --- a/internal/utilities/utilities.go +++ b/internal/utilities/utilities.go @@ -7,10 +7,12 @@ See the LICENSE file for more details. package utilities import ( + "bufio" "encoding/json" "errors" "fmt" "io/ioutil" + "net/http" "os" "strconv" "time" @@ -154,6 +156,7 @@ func CreateClusterDefinitionRecordFromRaw(gitAuth apiTypes.GitAuth, cliFlags typ GitProvider: gitProvider, GitProtocol: viper.GetString("flags.git-protocol"), DnsProvider: viper.GetString("flags.dns-provider"), + LogFileName: viper.GetString("k1-paths.log-file-name"), GitAuth: apiTypes.GitAuth{ Token: gitAuth.Token, User: gitAuth.User, @@ -247,3 +250,36 @@ func ExportCluster(cluster apiTypes.Cluster, kcfg *k8s.KubernetesClient) error { return nil } + +func ConsumeStream(url string) { + client := &http.Client{} + + req, err := http.NewRequest("GET", url, nil) + if err != nil { + fmt.Println("Error creating request:", err) + return + } + + resp, err := client.Do(req) + if err != nil { + fmt.Println("Error making request:", err) + return + } + + if resp.StatusCode != http.StatusOK { + fmt.Println("Error response:", resp.Status) + return + } + + // Read and print the streamed data until done signal is received + scanner := bufio.NewScanner(resp.Body) + for scanner.Scan() { + data := scanner.Text() + log.Info().Msgf(data) + } + + if err := scanner.Err(); err != nil { + log.Error().Msgf("Error reading response: %s", err.Error()) + return + } +} diff --git a/main.go b/main.go index 2cd8b91d8..8dd0e833d 100644 --- a/main.go +++ b/main.go @@ -12,9 +12,9 @@ import ( "os" "time" - "github.com/rs/zerolog" "golang.org/x/exp/slices" + zeroLog "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/kubefirst/kubefirst/cmd" @@ -27,7 +27,7 @@ import ( func main() { argsWithProg := os.Args - bubbleTeaBlacklist := []string{"completion", "help", "--help", "-h", "quota"} + bubbleTeaBlacklist := []string{"completion", "help", "--help", "-h", "quota", "logs"} canRunBubbleTea := true if argsWithProg != nil { @@ -40,8 +40,39 @@ func main() { } } + config := configs.ReadConfig() + if err := pkg.SetupViper(config, true); err != nil { + stdLog.Panic(err) + } + now := time.Now() epoch := now.Unix() + logfileName := fmt.Sprintf("log_%d.log", epoch) + + isProvision := slices.Contains(argsWithProg, "create") + isLogs := slices.Contains(argsWithProg, "logs") + + // don't create a new log file for logs, using the previous one + if isLogs { + logfileName = viper.GetString("k1-paths.log-file-name") + } + + // use cluster name as filename + if isProvision { + clusterName := fmt.Sprint(epoch) + for i := 1; i < len(os.Args); i++ { + arg := os.Args[i] + + // Check if the argument is "--cluster-name" + if arg == "--cluster-name" && i+1 < len(os.Args) { + // Get the value of the cluster name + clusterName = os.Args[i+1] + break + } + } + + logfileName = fmt.Sprintf("log_%s.log", clusterName) + } homePath, err := os.UserHomeDir() if err != nil { @@ -66,7 +97,7 @@ func main() { } //* create session log file - logfile := fmt.Sprintf("%s/log_%d.log", logsFolder, epoch) + logfile := fmt.Sprintf("%s/%s", logsFolder, logfileName) logFileObj, err := pkg.OpenLogFile(logfile) if err != nil { stdLog.Panicf("unable to store log location, error is: %s - please verify the current user has write access to this directory", err) @@ -84,18 +115,14 @@ func main() { // this Go standard log is active to keep compatibility with current code base stdLog.SetOutput(logFileObj) stdLog.SetPrefix("LOG: ") - stdLog.SetFlags(stdLog.Ldate | stdLog.Lmicroseconds | stdLog.Llongfile) - - // setup Zerolog - log.Logger = pkg.ZerologSetup(logFileObj, zerolog.InfoLevel) + stdLog.SetFlags(stdLog.Ldate) - config := configs.ReadConfig() - if err = pkg.SetupViper(config); err != nil { - stdLog.Panic(err) - } + log.Logger = zeroLog.New(logFileObj).With().Timestamp().Logger() viper.Set("k1-paths.logs-dir", logsFolder) - viper.Set("k1-paths.log-file", fmt.Sprintf("%s/log_%d.log", logsFolder, epoch)) + viper.Set("k1-paths.log-file", logfile) + viper.Set("k1-paths.log-file-name", logfileName) + err = viper.WriteConfig() if err != nil { stdLog.Panicf("unable to set log-file-location, error is: %s", err)