From 422ee93b445e93bde75970c9d755aac6a3a1fdf4 Mon Sep 17 00:00:00 2001 From: gilex-dev Date: Fri, 1 Sep 2023 23:42:19 +0200 Subject: [PATCH] add viper configuration & logger --- .YetAnotherToDoList.yaml | 3 ++ cmd/root.go | 85 +++++++++++++++++++++++++++++++++++----- cmd/server.go | 37 +++++++++-------- server/main.go | 19 +++------ 4 files changed, 103 insertions(+), 41 deletions(-) create mode 100644 .YetAnotherToDoList.yaml diff --git a/.YetAnotherToDoList.yaml b/.YetAnotherToDoList.yaml new file mode 100644 index 0000000..932fd84 --- /dev/null +++ b/.YetAnotherToDoList.yaml @@ -0,0 +1,3 @@ +log_file: "YetAnotherToDoList.log" +log_UTC: false +port: 4242 diff --git a/cmd/root.go b/cmd/root.go index a908ccd..7971cce 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -18,24 +18,26 @@ package cmd import ( "fmt" + "log" "os" + "path/filepath" + "strings" + "time" "github.com/spf13/cobra" "github.com/spf13/viper" ) var cfgFile string +var logger *log.Logger // rootCmd represents the base command when called without any subcommands var rootCmd = &cobra.Command{ Use: "YetAnotherToDoList", - Short: "A brief description of your application", - Long: `A longer description that spans multiple lines and likely contains -examples and usage of using your application. For example: - -Cobra is a CLI library for Go that empowers applications. -This application is a tool to generate the needed files -to quickly create a Cobra application.`, + Short: "A simple To Do List Web Application with Go backend, Vue.js frontend and a GraphQL API", + Long: `YetAnotherToDoList 2023 by gilex-dev +A simple To Do List Web Application with Go backend, Vue.js frontend and a GraphQL API +`, // Uncomment the following line if your bare application // has an action associated with it: // Run: func(cmd *cobra.Command, args []string) { }, @@ -51,17 +53,18 @@ func Execute() { } func init() { - cobra.OnInitialize(initConfig) + cobra.OnInitialize(initConfig, initLog) // Here you will define your flags and configuration settings. // Cobra supports persistent flags, which, if defined here, // will be global for your application. rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.YetAnotherToDoList.yaml)") + rootCmd.PersistentFlags().String("log_file", "", "Path to log file") // Cobra also supports local flags, which will only run // when this action is called directly. - rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + // rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") } // initConfig reads in config file and ENV variables if set. @@ -74,8 +77,13 @@ func initConfig() { home, err := os.UserHomeDir() cobra.CheckErr(err) + wd, err := os.Getwd() + cobra.CheckErr(err) + // Search config in home directory with name ".YetAnotherToDoList" (without extension). viper.AddConfigPath(home) + // Search config in working directory with name ".YetAnotherToDoList" (without extension). + viper.AddConfigPath(wd) viper.SetConfigType("yaml") viper.SetConfigName(".YetAnotherToDoList") } @@ -85,5 +93,64 @@ func initConfig() { // If a config file is found, read it in. if err := viper.ReadInConfig(); err == nil { fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed()) + } else { + fmt.Fprintln(os.Stderr, "Unable to read in", viper.ConfigFileUsed(), err) } } + +func initLog() { + var utc = 0 + var time_zone_use, time_zone_alt string + + time_zone_local, _ := time.Now().Zone() + time_zone_offset := strings.Split(time.Now().In(time.Local).String(), " ")[2] + + if viper.GetBool("log_UTC") { + utc = log.LUTC + time_zone_use = "UTC" + time_zone_alt = time_zone_local + time_zone_offset_rune := []rune(time_zone_offset) + + if time_zone_offset_rune[0] == '+' { + time_zone_offset_rune[0] = '-' + } + + time_zone_offset = string(time_zone_offset_rune) + + } else { + time_zone_use = time_zone_local + time_zone_alt = "UTC" + } + + logger_flags := log.Ldate | log.Ltime | utc + logger = log.New(os.Stdout, "", logger_flags) + + if err := viper.BindPFlag("log_file", rootCmd.Flags().Lookup("log_file")); err != nil { + fmt.Println("Unable to bind flag:", err) + } + + if viper.GetString("log_file") != "" { + + log_path, err := filepath.Abs(viper.GetString("log_file")) + + logger.SetOutput(os.Stdout) + if err != nil { + logger.Println("Invalid path for log file", log_path) + } + + log_file, err := os.OpenFile(log_path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) + + if err != nil { + fmt.Println("Failed to write to log file:", err) + } else { + logger.Println("Switching to log file", log_path) + logger.SetOutput(log_file) + } + } + + logger.SetFlags(0) + logger.Println() + logger.SetFlags(logger_flags) + logger.Printf("Started YetAnotherToDoList with pid: %v\n", os.Getpid()) + logger.Printf("Using %v (%v %v) in logs", time_zone_use, time_zone_alt, time_zone_offset) +} diff --git a/cmd/server.go b/cmd/server.go index 68e36a4..b5127d7 100644 --- a/cmd/server.go +++ b/cmd/server.go @@ -1,36 +1,33 @@ /* -YetAnotherToDoList -Copyright © 2023 gilex-dev gilex-dev@proton.me - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 3. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . +Copyright © 2023 NAME HERE */ package cmd import ( "fmt" - "github.com/spf13/cobra" "somepi.ddns.net/gitea/gilex-dev/YetAnotherToDoList/server" + + "github.com/spf13/cobra" + "github.com/spf13/viper" ) // serverCmd represents the server command var serverCmd = &cobra.Command{ Use: "server", - Short: "Start web server", - Long: `Start the web server with a GraphQL playground`, + Short: "Start the http server", + Long: ``, Run: func(cmd *cobra.Command, args []string) { - fmt.Println("server called") - server.StartServer() + + if err := viper.BindPFlag("debug", cmd.Flags().Lookup("debug")); err != nil { + fmt.Println("Unable to bind flag:", err) + } + if err := viper.BindPFlag("port", cmd.Flags().Lookup("port")); err != nil { + fmt.Println("Unable to bind flag:", err) + } + + logger.Println("starting http server...") + server.StartServer(logger, viper.GetInt("port")) }, } @@ -46,4 +43,6 @@ func init() { // Cobra supports local flags which will only run when this command // is called directly, e.g.: // serverCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + serverCmd.Flags().BoolP("debug", "d", false, "Enable debugging") + serverCmd.Flags().IntP("port", "p", 4242, "The port to listen on") } diff --git a/server/main.go b/server/main.go index 3c58dd2..5099640 100644 --- a/server/main.go +++ b/server/main.go @@ -19,26 +19,19 @@ package server import ( "log" "net/http" - "os" + "strconv" "github.com/99designs/gqlgen/graphql/handler" "github.com/99designs/gqlgen/graphql/playground" "somepi.ddns.net/gitea/gilex-dev/YetAnotherToDoList/graph" ) -const defaultPort = "8080" - -func StartServer() { - port := os.Getenv("PORT") - if port == "" { - port = defaultPort - } - +func StartServer(logger *log.Logger, port int) { srv := handler.NewDefaultServer(graph.NewExecutableSchema(graph.Config{Resolvers: &graph.Resolver{}})) - http.Handle("/", playground.Handler("GraphQL playground", "/query")) - http.Handle("/query", srv) + http.Handle("/", playground.Handler("GraphQL playground", "/api")) - log.Printf("connect to http://localhost:%s/ for GraphQL playground", port) - log.Fatal(http.ListenAndServe(":"+port, nil)) + http.Handle("/api", srv) + logger.Printf("connect to http://localhost:%v/ for GraphQL playground", port) + logger.Fatal(http.ListenAndServe(":"+strconv.FormatInt(int64(port), 10), nil)) }