From e7bb2639cdb94270b80ae07e82d641c595d21427 Mon Sep 17 00:00:00 2001 From: "pakintada@gmail.com" Date: Fri, 22 Sep 2023 16:54:52 +0700 Subject: [PATCH] add display merged files. WIP json display --- .../changelog/changelog.component.html | 60 ++++++- .../features/changelog/changelog.component.ts | 44 ++++- .../src/app/features/merge/merge.component.ts | 4 +- .../app/shared/services/fetch-log.service.ts | 10 +- server/config/config.go | 1 + server/server.go | 153 +++++++++++++++--- server/services/logger/logger.go | 22 ++- 7 files changed, 250 insertions(+), 44 deletions(-) diff --git a/client/src/app/features/changelog/changelog.component.html b/client/src/app/features/changelog/changelog.component.html index c085c6d..be64813 100644 --- a/client/src/app/features/changelog/changelog.component.html +++ b/client/src/app/features/changelog/changelog.component.html @@ -5,7 +5,7 @@
- +
@@ -14,16 +14,64 @@
+ + + +
+
+ +
+
+
+
+ + +
+ + +
-
-
-
-

{{logfile}}

- +
+ +

Log files

+
+
+
+

{{logfile}}

+ +
+ +
+ + +
+

Merged files

+
+
+ + +
+

{{logfile}}

+ +
+ +
+
+ + +
+ + + + +
diff --git a/client/src/app/features/changelog/changelog.component.ts b/client/src/app/features/changelog/changelog.component.ts index 2e160d9..f39e6b0 100644 --- a/client/src/app/features/changelog/changelog.component.ts +++ b/client/src/app/features/changelog/changelog.component.ts @@ -15,7 +15,9 @@ import { FetchLogService } from 'src/app/shared/services/fetch-log.service'; export class ChangelogComponent { public displayableLogs: string[] = []; + public displayableMergeJson: string[] = []; showLogModal:boolean = false; + showMergeModal:boolean = false; constructor( private httpClient: HttpClient, @@ -28,7 +30,7 @@ export class ChangelogComponent { // TODO: Fetch changelog.html // fetch("/changelog") let dirlist: any[] = [] - this.httpClient.get(environment.api+"/mergelogList", { + this.httpClient.get(environment.api+"/listFileInDir/changelog", { withCredentials: true }).subscribe({ next: (value) => { @@ -45,7 +47,26 @@ export class ChangelogComponent { console.error('Error fetch json: ',err); } }) - console.log(dirlist); + // console.log(dirlist); + + this.httpClient.get(environment.api+"/listFileInDir/merge", { + withCredentials: true + }).subscribe({ + next: (value) => { + console.log(value) + if(typeof value === "object" && value !== null){ + if("dirs" in value){ + console.log("dirs", value) + // dirlist.push(...(value as {dirs: unknown[]})["dirs"]); + this.displayableMergeJson = value.dirs as any[]; + } + } + }, + error: (err) => { + console.error('Error fetch json: ',err); + } + }) + return dirlist; } @@ -70,11 +91,22 @@ export class ChangelogComponent { viewLog(name:string){ let cli = new FetchLogService(this.httpClient); this.showLogModal = !this.showLogModal; - cli.fetchLogsToDisplay("", true, false, name); - cli.fetchLogsToDisplay("", false, false, name); + cli.fetchLogsToDisplay("changelog", true, false, name); + cli.fetchLogsToDisplay("changelog", false, false, name); } - toggleLogModal(){ - this.showLogModal = !this.showLogModal; + viewJson(name:string){ + let cli = new FetchLogService(this.httpClient); + this.showMergeModal = !this.showMergeModal; + cli.fetchLogsToDisplay("merge", false, true, name); + // cli.fetchLogsToDisplay("", false, false, name); + } + + toggleLogModal(target:string){ + if(target == "merge"){ + this.showMergeModal = !this.showMergeModal; + } else { + this.showLogModal = !this.showLogModal; + } } } diff --git a/client/src/app/features/merge/merge.component.ts b/client/src/app/features/merge/merge.component.ts index e381ba3..8a5cc9c 100644 --- a/client/src/app/features/merge/merge.component.ts +++ b/client/src/app/features/merge/merge.component.ts @@ -79,7 +79,7 @@ export class MergeComponent { // fetch log file // this.fetchLogsToDisplay("", false, false); // fetch json - this.mergeLogs = new FetchLogService(this.httpClient).fetchLogsToDisplay("", false, true,""); + this.mergeLogs = new FetchLogService(this.httpClient).fetchLogsToDisplay("", false, true,this.targets.changelog_path); this.chlog.fetchLoglist(); this.chlog.translateLogDirToString(); } @@ -87,6 +87,4 @@ export class MergeComponent { }, }) } - - } diff --git a/client/src/app/shared/services/fetch-log.service.ts b/client/src/app/shared/services/fetch-log.service.ts index 59decf9..6edfa07 100644 --- a/client/src/app/shared/services/fetch-log.service.ts +++ b/client/src/app/shared/services/fetch-log.service.ts @@ -15,12 +15,7 @@ export class FetchLogService { public fetchLogsToDisplay(query: string, isDisplayOnly: boolean, requestJson: boolean, filename:string) : Map | void{ - let additionalParams:string = "?query="; - if(query != ""){ - additionalParams += query - } else { - additionalParams = "" - } + let additionalParams:string = "?query="+query; let jsontarget; @@ -35,6 +30,9 @@ export class FetchLogService { }).subscribe({ next: (value: any) => { jsontarget = value; + if(query == "merge"){ + document.getElementById("merge-json-disp-texts")!.innerHTML = jsontarget; + } }, error: (err: any) => { console.error('Error fetch json: ',err); diff --git a/server/config/config.go b/server/config/config.go index 245c910..e038a40 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -5,4 +5,5 @@ type ServerConfig struct { AllowedOrigins string `mapstructure:"ALLOWED_ORIGINS"` ClientRedirectURL string `mapstructure:"CLIENT_REDIRECT_URL"` ServerDomain string `mapstructure:"SERVER_DOMAIN"` + Debug bool `mapstructure:"DEBUG_MODE"` } diff --git a/server/server.go b/server/server.go index d82d221..9bdc4c2 100644 --- a/server/server.go +++ b/server/server.go @@ -78,8 +78,14 @@ func (s *Server) Run() error { // logger // defer log_inst.Sync() + if s.cfg.Debug { + // logger.SetLevel("DEBUG") + Log.Debug("Debug mode", zap.Bool("enable", s.cfg.Debug)) + logger.EnableDebug(s.cfg.Debug) + } + s.createHandler() - log.Printf("Server running on %s", s.server.Addr) + // log.Printf("Server running on %s", s.server.Addr) Log.Info("Server running", zap.String("addr", s.server.Addr)) return s.server.ListenAndServe() } @@ -134,8 +140,11 @@ func (s *Server) createHandler() { } ctx := context.WithValue(r.Context(), "user", user) - - Log.Info("User is authenticated", zap.String("user", user.Name)) + if user == nil { + Log.Error("User is not authenticated or timed out", zap.Any("requester", user)) + } else { + Log.Info("User is authenticated", zap.String("user", user.Name)) + } next.ServeHTTP(w, r.WithContext(ctx)) }) @@ -147,7 +156,7 @@ func (s *Server) createHandler() { err := json.NewDecoder(r.Body).Decode(&targetMap) if err != nil { w.WriteHeader(http.StatusBadRequest) - log.Fatalln("Merge request failed: ", err) + Log.Fatal("Merge request failed", zap.Error(err)) return } repo_path := "cofffeemachineConfig/coffeethai02_" @@ -160,12 +169,12 @@ func (s *Server) createHandler() { // find target file in the cofffeemachineConfig if _, err := os.Stat(repo_path + master_version + ".json"); err != nil { w.WriteHeader(http.StatusBadRequest) - log.Fatalln("Merge request failed. Master file not found: ", err) + Log.Fatal("Merge request failed. Master file not found: ", zap.Error(err)) return } if _, err := os.Stat(repo_path + dev_version + ".json"); err != nil { w.WriteHeader(http.StatusBadRequest) - log.Fatalln("Merge request failed. Dev file not found: ", err) + Log.Fatal("Merge request failed. Dev file not found: ", zap.Error(err)) return } @@ -174,45 +183,58 @@ func (s *Server) createHandler() { // Get who's requesting user := r.Context().Value("user").(*models.User) + Log.Info("Request merge by", zap.String("user", user.Name)) // lookup for python exec py_exec, err := exec.LookPath("python") if err != nil { - log.Fatalln("Python error: ", err) + Log.Fatal("Python error: ", zap.Error(err)) } else { py_exec, err = filepath.Abs(py_exec) } - log.Println("Found python exec: ", py_exec) + Log.Info("Found python exec: ", zap.String("PythonPath", py_exec)) // target api file merge_api, api_err := os.Open("./python_api/merge_recipe.py") if api_err != nil { - log.Fatalln("Merge request failed. Python api error: ", api_err) + Log.Fatal("Merge request failed. Python api error: ", zap.String("ApiErr", api_err.Error())) } defer merge_api.Close() - log.Println("Locate python api", merge_api.Name()) + // log.Println("Locate python api", merge_api.Name()) + Log.Info("Locate python api", zap.String("ApiName", merge_api.Name())) cmd := exec.Command(py_exec, merge_api.Name(), "merge", master_path, dev_path, output_path, changelog_path, "", user.Name) - log.Println("Run merge command", cmd) + // log.Println("Run merge command", cmd) + Log.Info("Merge", zap.String("master", master_path), zap.String("dev", dev_path), zap.String("output", output_path)) + Log.Debug("Run merge command", zap.String("Command", cmd.String())) out, err := cmd.CombinedOutput() - log.Println(string(out)) + // log.Println(string(out)) + Log.Debug("Merge output", zap.String("Output", string(out))) if err != nil { - log.Fatalln("Merge request failed. Python merge failed: ", err) + // log.Fatalln("Merge request failed. Python merge failed: ", err) + Log.Fatal("Merge request failed. Python merge failed", zap.Error(err)) } w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(map[string]string{"message": "Merge success"}) - + Log.Info("Merge success", zap.String("output", "merge success")) }) r.Post("/dllog", func(w http.ResponseWriter, r *http.Request) { + Log.Debug("Request uri = ", zap.String("uri", r.RequestURI)) + + Log.Debug("Query param = ", zap.String("query", r.URL.Query().Get("query"))) + // param + param := r.URL.Query().Get("query") var postRequest map[string]interface{} err := json.NewDecoder(r.Body).Decode(&postRequest) + Log.Debug("Log request: ", zap.String("postRequest", fmt.Sprintf("%+v", postRequest))) + if err != nil { w.WriteHeader(http.StatusBadRequest) - log.Fatalln("Log request failed: ", err) + Log.Fatal("Decode in request failed: ", zap.Error(err)) return } @@ -228,11 +250,23 @@ func (s *Server) createHandler() { } log_name := postRequest["filename"].(string) + Log.Warn("Log file name: ", zap.String("filename", log_name)) + + if log_name == "" { + Log.Fatal("Empty log file name") + } // log.Println("Log file ext: ", file_ext) - changelog_path := "cofffeemachineConfig/changelog/" + log_name + file_ext + default_changelog_path := "cofffeemachineConfig/" + param + "/" + + changelog_path := default_changelog_path + log_name + file_ext + if strings.Contains(log_name, default_changelog_path) && strings.Contains(log_name, ".json") { + changelog_path = log_name + } + logFile, err := os.Open(changelog_path) if err != nil { + Log.Fatal("Log request failed: ", zap.Error(err)) http.Error(w, err.Error(), http.StatusInternalServerError) } @@ -243,19 +277,20 @@ func (s *Server) createHandler() { var logFileJson map[string]interface{} err = json.NewDecoder(logFile).Decode(&logFileJson) if err != nil { - log.Fatalf("Error when decode log file: %s", err) + Log.Fatal("Error when decode log file: ", zap.Error(err)) } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(logFileJson) - log.Println("Log file: ", changelog_path) + Log.Info("Log file: ", zap.String("filename", log_name)) } else { w.Header().Set("Content-Disposition", "attachment; filename=logfile"+file_ext) w.Header().Set("Content-Type", "application/octet-stream") _, err = io.Copy(w, logFile) if err != nil { + Log.Fatal("Could not send blob", zap.Error(err)) http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -266,6 +301,7 @@ func (s *Server) createHandler() { r.Get("/mergelogList", func(w http.ResponseWriter, r *http.Request) { ch_dir, err := os.ReadDir("cofffeemachineConfig/changelog") if err != nil { + Log.Error("Error while trying to read dir: ", zap.String("dir", "cofffeemachineConfig/changelog"), zap.Error(err)) http.Error(w, err.Error(), http.StatusInternalServerError) } displayable := make([]string, 0) @@ -281,6 +317,87 @@ func (s *Server) createHandler() { json.NewEncoder(w).Encode(map[string][]string{"dirs": displayable}) }) + r.Get("/listFileInDir/*", func(w http.ResponseWriter, r *http.Request) { + + // target_dir, err := os.ReadDir("cofffeemachineConfig") + + // spl + spl_path := strings.Split(r.RequestURI, "/") + if len(spl_path) > 3 { + Log.Warn("Unexpected depth: ", + zap.String("path", r.RequestURI), + zap.String("depth", fmt.Sprintf("%d", len(spl_path)))) + } + + if spl_path[2] == "" { + Log.Error("Empty target dir", zap.String("path", r.RequestURI)) + } + + Log.Debug("Split path = ", zap.Any("paths", spl_path)) + + // Log.Info("Target dir: ", zap.String("dir", "cofffeemachineConfig")) + + main_folder := "cofffeemachineConfig" + target_path := main_folder + "/" + spl_path[2] + + dir, err := os.ReadDir(target_path) + if err != nil { + Log.Error("Error while trying to read dir: ", zap.String("dir", target_path), zap.Error(err)) + http.Error(w, err.Error(), http.StatusInternalServerError) + } + + // File ext + file_ext := ".json" + switch spl_path[2] { + case "changelog": + file_ext = ".html" + break + case "merge": + file_ext = ".json" + break + } + Log.Debug("Set file ext = ", zap.String("file_ext", file_ext)) + + displayable := make([]string, 0) + for _, file := range dir { + if strings.Contains(file.Name(), file_ext) { + Log.Debug("Found file: ", zap.String("file", file.Name())) + displayable = append(displayable, file.Name()[:len(file.Name())-len(filepath.Ext(file.Name()))]) + } + } + + // send back + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(map[string][]string{"dirs": displayable}) + Log.Debug("Scan dir completed < ", zap.String("path", r.RequestURI)) + }) + + // dl merged json file + // r.Get("/dlmerged", func(w http.ResponseWriter, r *http.Request) { + + // }) + + r.Get("/mergefileList", func(w http.ResponseWriter, r *http.Request) { + merge_dir, err := os.ReadDir("cofffeemachineConfig/merge") + if err != nil { + Log.Error("Error while trying to read dir: ", zap.String("dir", "cofffeemachineConfig/merge"), zap.Error(err)) + http.Error(w, err.Error(), http.StatusInternalServerError) + } + + displayable := make([]string, 0) + + for _, file := range merge_dir { + if strings.Contains(file.Name(), ".json") { + displayable = append(displayable, file.Name()[:len(file.Name())-len(filepath.Ext(file.Name()))]) + } + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(map[string][]string{"dirs": displayable}) + }) + // Recipe Router rr := routers.NewRecipeRouter(database) rr.Route(r) diff --git a/server/services/logger/logger.go b/server/services/logger/logger.go index cf4597f..9cca1d9 100644 --- a/server/services/logger/logger.go +++ b/server/services/logger/logger.go @@ -9,12 +9,17 @@ import ( ) var ( - log_inst = NewLogger() + log_inst = _NewLogger() + + enable_debug = false + log_level = zap.NewAtomicLevel() + log_file_config = zapcore.AddSync(&lumberjack.Logger{ Filename: "services/logger/serverlog.log", MaxSize: 500, // megabytes MaxBackups: 3, MaxAge: 28, //days + LocalTime: true, }) json_enc = zapcore.NewJSONEncoder(zapcore.EncoderConfig{ TimeKey: "timestamp", @@ -36,17 +41,20 @@ var ( ) func createLogggerConfig() *zap.Logger { - log_level := zap.NewAtomicLevelAt(zap.InfoLevel) + + enable_debug_mode := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { + return lvl >= zap.InfoLevel || enable_debug + }) log_core := zapcore.NewTee( - zapcore.NewCore(json_enc, log_file_config, log_level), - zapcore.NewCore(console_enc, zapcore.AddSync(os.Stdout), log_level), + zapcore.NewCore(json_enc, log_file_config, enable_debug_mode), + zapcore.NewCore(console_enc, zapcore.AddSync(os.Stdout), enable_debug_mode), ) return zap.New(log_core) } -func NewLogger() *zap.Logger { +func _NewLogger() *zap.Logger { log := createLogggerConfig() defer log.Sync() return log @@ -55,3 +63,7 @@ func NewLogger() *zap.Logger { func GetInstance() *zap.Logger { return log_inst } + +func EnableDebug(state bool) { + enable_debug = state +}