Browse Source

First Alpha Version Done.

zry 4 years ago
parent
commit
8ef050cdbe

+ 55 - 0
blankBackend/main.go

@@ -0,0 +1,55 @@
+package main
+
+import (
+	"fmt"
+	"github.com/gin-gonic/gin"
+	"github.com/gorilla/websocket"
+	"net/http"
+	"os"
+)
+
+var ListenAddress string
+
+var upGrader = websocket.Upgrader{
+	CheckOrigin: func(r *http.Request) bool {
+		return true
+	},
+}
+
+func ping(c *gin.Context) {
+	ws, err := upGrader.Upgrade(c.Writer, c.Request, nil)
+	if err != nil {
+		return
+	}
+	defer ws.Close()
+	for {
+		mt, message, err := ws.ReadMessage()
+		if err != nil {
+			break
+		}
+		if string(message) == "ping" {
+			message = []byte("pong")
+		}
+		err = ws.WriteMessage(mt, message)
+		if err != nil {
+			break
+		}
+	}
+}
+
+func main() {
+	ListenAddress = os.Getenv("listen")
+	if ListenAddress == "" {
+		fmt.Println("No environment variable 'listen', use default value ':9090'")
+		ListenAddress = ":9090"
+	}
+	r := gin.Default()
+	r.GET("/api/ws/ping", ping)
+	r.GET("/api/hello", hello)
+	r.Run(ListenAddress)
+}
+
+func hello(context *gin.Context) {
+	context.Writer.WriteString("hello")
+	context.Status(200)
+}

+ 38 - 10
defaultFrontend/access_log.go

@@ -4,6 +4,7 @@ import (
 	"fmt"
 	"io"
 	"strconv"
+	"time"
 )
 
 type AccessLoggerLevelConfig struct {
@@ -96,27 +97,54 @@ func NewAccessLogger() *AccessLogger {
 	}
 }
 
-func (this *AccessLogger) UseLogger(wr io.Writer, lvcfg *AccessLoggerLevelConfig) {
+func (this *AccessLogger) UseLogger(wr io.Writer, lvcfg *AccessLoggerLevelConfig, fmtstr string, useutc bool) {
 	this.enable = true
 	this.level_config = lvcfg
 	this.commonLogger = NewCommonLogger(lvcfg.OutputLevel, wr)
+	exdmap := map[string]int{
+		"level":   8,
+		"status":  3,
+		"latency": 8,
+		"cip":     20,
+		"method":  8,
+		"url":     1024,
+	}
+	this.commonLogger.SetFormatterWithCustomExData(fmtstr, exdmap, useutc)
 }
 
-func (this *AccessLogger) Emit(level DWSILogLevel, url string, status int) {
+func (this *AccessLogger) transStatusCode2Level(code int) DWSILogLevel {
+	switch code {
+	case 200:
+		return this.level_config.SuccessLevel
+	case 404:
+		return this.level_config.NotFoundLevel
+	case 403:
+		return this.level_config.ForbiddenLevel
+	case 502:
+		return this.level_config.GatewayErrorLevel
+	case 500:
+		return this.level_config.InternalErrorLevel
+	default:
+		return this.level_config.SuccessLevel
+	}
+}
+
+func (this *AccessLogger) Emit(tm time.Time, status int,
+	latency time.Duration, cip string, method string, url string) {
 	if this.enable {
+		level := this.transStatusCode2Level(status)
 		if level == LogLv_INVALID {
 			return
 		}
 		lvstr := transLevelIntoLevelString(level)
 		exd := map[string]string{
-			"level":  lvstr,
-			"status": strconv.Itoa(status),
-			"url":    url,
+			"level":   lvstr,
+			"status":  strconv.Itoa(status),
+			"latency": fmt.Sprintf("%v", latency),
+			"cip":     cip,
+			"method":  method,
+			"url":     url,
 		}
-		this.commonLogger.RawEmit(level, exd)
+		this.commonLogger.RawEmitWithCustomTime(level, tm, exd)
 	}
 }
-
-func (this *AccessLogger) LogResponse() {
-	// TODO: Fix
-}

+ 44 - 13
defaultFrontend/common_log.go

@@ -48,32 +48,57 @@ func (this *CommonLogger) SetWriter(wr io.Writer) {
 	this.log_writter = wr
 }
 
-func (this *CommonLogger) SetFormatter(fmtstr string) {
+func (this *CommonLogger) SetFormatter(fmtstr string, useutc bool) {
+	exdmap := map[string]int{
+		"level": 8,
+		"unit":  32,
+		"msg":   2048,
+	}
+	this.SetFormatterWithCustomExData(fmtstr, exdmap, useutc)
+}
+
+func (this *CommonLogger) SetFormatterWithCustomExData(fmtstr string, exlist map[string]int, useutc bool) {
 	tpe := timefmt.NewTimePrinterEx()
 	parser := timefmt.NewFormatParser(true)
-	parser.AddExDataTag("level", func() timefmt.TimeElementEx {
-		return tfelem.NewExDataElement(8, "level")
-	})
-	parser.AddExDataTag("unit", func() timefmt.TimeElementEx {
-		return tfelem.NewExDataElement(32, "unit")
-	})
-	parser.AddExDataTag("msg", func() timefmt.TimeElementEx {
-		return tfelem.NewExDataElement(2048, "msg")
-	})
+	for k, v := range exlist {
+		sz := v
+		nm := k
+		parser.AddExDataTag(k, func() timefmt.TimeElementEx {
+			return tfelem.NewExDataElement(sz, nm)
+		})
+	}
 	tfe := timefmt.NewTimeFormatterEx(tpe, parser, true)
+	tfe.ParseFormat(fmtstr)
+	if useutc {
+		tfe.ForceUTC()
+	} else {
+		tfe.ForceLocalTimezone()
+	}
 	this.formatter = tfe
 }
 
 func (this *CommonLogger) SetDefaultFormatter() {
-	this.SetFormatter(loggerDefaultFormatString)
+	this.SetFormatter(loggerDefaultFormatString, false)
 }
 
 func (this *CommonLogger) RawEmit(lv DWSILogLevel, exdata map[string]string) {
-	s := this.formatter.Format(time.Now(), exdata)
-	_, _ = this.log_writter.Write([]byte(s))
+	this.RawEmitWithCustomTime(lv, time.Now(), exdata)
+}
+
+func (this *CommonLogger) RawEmitWithCustomTime(lv DWSILogLevel, timeparam time.Time, exdata map[string]string) {
+	if lv <= this.output_level {
+		s := this.formatter.Format(timeparam, exdata)
+		_, err := fmt.Fprint(this.log_writter, s)
+		if err != nil {
+			fmt.Println("Failed Write Log: ", s)
+		}
+	}
 }
 
 func (this *CommonLogger) Emit(lv DWSILogLevel, unit string, msg string) {
+	if lv > this.output_level {
+		return
+	}
 	if lv == LogLv_INVALID {
 		return
 	}
@@ -87,11 +112,17 @@ func (this *CommonLogger) Emit(lv DWSILogLevel, unit string, msg string) {
 }
 
 func (this *CommonLogger) EmitF(lv DWSILogLevel, unit string, fmtstr string, a ...interface{}) {
+	if lv > this.output_level {
+		return
+	}
 	s := fmt.Sprintf(fmtstr, a...)
 	this.Emit(lv, unit, s)
 }
 
 func (this *CommonLogger) EmitN(lv DWSILogLevel, unit string, a ...interface{}) {
+	if lv > this.output_level {
+		return
+	}
 	s := fmt.Sprint(a...)
 	this.Emit(lv, unit, s)
 }

+ 23 - 3
defaultFrontend/main.go

@@ -25,6 +25,7 @@ func main() {
 	GetConfigEnv()
 	ParseYAMLConfig()
 	InitLogger()
+	StartServer()
 }
 
 func GetConfigEnv() {
@@ -43,7 +44,7 @@ func GetConfigEnv() {
 	}
 	if BackendPrefix == "" {
 		fmt.Println("No environment variable 'backend_prefix', use default value 'api'")
-		BackendPrefix = ":8080"
+		BackendPrefix = "api"
 	}
 	if BackendTarget == "" {
 		fmt.Println("No environment variable 'backend_target', use default value 'http://localhost:9090/'")
@@ -80,6 +81,16 @@ func ParseYAMLConfig() {
 		fmt.Println("failed parse config YAML: ", err)
 		os.Exit(ExitCode_YAMLParseError)
 	}
+	if ConfigData.CommonConfig.IsDebugModeOn {
+		fmt.Println("Debug Mode is Enable.")
+		fmt.Println("Print All Config For Debug:")
+		tmpyaml, err := yaml.Marshal(ConfigData)
+		if err != nil {
+			fmt.Println("Failed Print Config: ", err)
+		} else {
+			fmt.Printf("%v\n\n", string(tmpyaml))
+		}
+	}
 }
 
 func InitLogger() {
@@ -92,8 +103,12 @@ func InitLogger() {
 		LocalTime:  cfg.UseLocalTime,
 		Compress:   cfg.Compress,
 	}
+	_, _ = fmt.Fprintln(elw, "Lumberjack Logger Write Test")
 	ErrorLog = NewCommonLogger(ErrorLogOutputLevel, elw)
-	ErrorLog.SetFormatter(ConfigData.LogConfig.ErrorLoggerDetailConfig.LogFormat)
+	ErrorLog.SetFormatter(
+		ConfigData.LogConfig.ErrorLoggerDetailConfig.LogFormat,
+		ConfigData.LogConfig.ErrorLoggerDetailConfig.UseUTC,
+	)
 	cfg = ConfigData.LogConfig.RollingLogConfig.AccessLogCfg
 	AccessLog = NewAccessLogger()
 	if ConfigData.LogConfig.AccessLogEnable {
@@ -105,6 +120,11 @@ func InitLogger() {
 			LocalTime:  cfg.UseLocalTime,
 			Compress:   cfg.Compress,
 		}
-		AccessLog.UseLogger(alw, AccessLogLevelConfigData)
+		AccessLog.UseLogger(
+			alw,
+			AccessLogLevelConfigData,
+			ConfigData.LogConfig.AccessLoggerDetailConfig.LogFormat,
+			ConfigData.LogConfig.AccessLoggerDetailConfig.UseUTC,
+		)
 	}
 }

+ 119 - 2
defaultFrontend/midware.go

@@ -1,7 +1,124 @@
 package main
 
-import "github.com/gin-gonic/gin"
+import (
+	"bytes"
+	"fmt"
+	"github.com/gin-gonic/gin"
+	"io/ioutil"
+	"net/http"
+	"net/http/httputil"
+	"runtime"
+	"time"
+)
 
-func CustomRecoveryMidware() gin.HandlerFunc {
+var (
+	crmchr_dunno     = []byte("???")
+	crmchr_centerDot = []byte("·")
+	crmchr_dot       = []byte(".")
+	crmchr_slash     = []byte("/")
+)
 
+func CustomAccessLogMidware(alogger *AccessLogger, elogger *CommonLogger) gin.HandlerFunc {
+	return func(context *gin.Context) {
+		start := time.Now()
+		path := context.Request.URL.Path
+		raw := context.Request.URL.RawQuery
+		context.Next()
+		end := time.Now()
+		latency := end.Sub(start)
+		clientIP := context.ClientIP()
+		method := context.Request.Method
+		statusCode := context.Writer.Status()
+		comment := context.Errors.ByType(gin.ErrorTypePrivate).String()
+		if raw != "" {
+			path = path + "?" + raw
+		}
+		alogger.Emit(start, statusCode, latency, clientIP, method, path)
+		if comment != "" {
+			elogger.EmitF(LogLv_WARN, "WebContext", "Web Context Error Info: %s", comment)
+		}
+	}
+}
+
+func CustomRecoveryMidware(logger *CommonLogger, isDebug bool) gin.HandlerFunc {
+	return func(context *gin.Context) {
+		defer func() {
+			if err := recover(); err != nil {
+				if logger != nil {
+					stack := stack(3)
+					if isDebug {
+						httprequest, _ := httputil.DumpRequest(context.Request, false)
+						msg := fmt.Sprintf("Panic recovered from error '%s':\n%s\n%s", err, string(httprequest), stack)
+						logger.Emit(LogLv_PANIC, "Recovery", msg)
+					} else {
+						msg := fmt.Sprintf("Panic recovered from error '%s':\n%s", err, stack)
+						logger.Emit(LogLv_PANIC, "Recovery", msg)
+					}
+				}
+				context.AbortWithStatus(http.StatusInternalServerError)
+			}
+		}()
+		context.Next()
+	}
+}
+
+// stack returns a nicely formatted stack frame, skipping skip frames.
+func stack(skip int) []byte {
+	buf := new(bytes.Buffer) // the returned data
+	// As we loop, we open files and read them. These variables record the currently
+	// loaded file.
+	var lines [][]byte
+	var lastFile string
+	for i := skip; ; i++ { // Skip the expected number of frames
+		pc, file, line, ok := runtime.Caller(i)
+		if !ok {
+			break
+		}
+		// Print this much at least.  If we can't find the source, it won't show.
+		fmt.Fprintf(buf, "%s:%d (0x%x)\n", file, line, pc)
+		if file != lastFile {
+			data, err := ioutil.ReadFile(file)
+			if err != nil {
+				continue
+			}
+			lines = bytes.Split(data, []byte{'\n'})
+			lastFile = file
+		}
+		fmt.Fprintf(buf, "\t%s: %s\n", function(pc), source(lines, line))
+	}
+	return buf.Bytes()
+}
+
+// source returns a space-trimmed slice of the n'th line.
+func source(lines [][]byte, n int) []byte {
+	n-- // in stack trace, lines are 1-indexed but our array is 0-indexed
+	if n < 0 || n >= len(lines) {
+		return crmchr_dunno
+	}
+	return bytes.TrimSpace(lines[n])
+}
+
+// function returns, if possible, the name of the function containing the PC.
+func function(pc uintptr) []byte {
+	fn := runtime.FuncForPC(pc)
+	if fn == nil {
+		return crmchr_dunno
+	}
+	name := []byte(fn.Name())
+	// The name includes the path name to the package, which is unnecessary
+	// since the file name is already included.  Plus, it has center dots.
+	// That is, we see
+	//	runtime/debug.*T·ptrmethod
+	// and want
+	//	*T.ptrmethod
+	// Also the package path might contains dot (e.g. code.google.com/...),
+	// so first eliminate the path prefix
+	if lastslash := bytes.LastIndex(name, crmchr_slash); lastslash >= 0 {
+		name = name[lastslash+1:]
+	}
+	if period := bytes.Index(name, crmchr_dot); period >= 0 {
+		name = name[period+1:]
+	}
+	name = bytes.Replace(name, crmchr_centerDot, crmchr_dot, -1)
+	return name
 }

+ 101 - 2
defaultFrontend/server.go

@@ -1,10 +1,109 @@
 package main
 
-import "github.com/gin-gonic/gin"
+import (
+	"fmt"
+	"github.com/gin-gonic/gin"
+	"github.com/yhat/wsutil"
+	"net/http"
+	"net/http/httputil"
+	"net/url"
+	"os"
+	"path"
+	"strings"
+)
 
 var ServerEngine *gin.Engine
+var StaticFileSystem http.FileSystem
+var FileServer http.Handler
+var ReverseProxyRemote *url.URL
 
 func StartServer() {
+	ErrorLog.Emit(LogLv_INFO, "Server", "HTTP Server Starting...")
 	ServerEngine = gin.New()
-	ServerEngine.Use(gin.Recovery())
+	if ConfigData.CommonConfig.IsDebugModeOn {
+		gin.SetMode(gin.DebugMode)
+	} else {
+		gin.SetMode(gin.ReleaseMode)
+	}
+	ServerEngine.Use(CustomRecoveryMidware(ErrorLog, ConfigData.CommonConfig.IsDebugModeOn))
+	ServerEngine.Use(CustomAccessLogMidware(AccessLog, ErrorLog))
+	ErrorLog.Emit(LogLv_INFO, "Server", "Loading URL Router...")
+	StaticFileSystem = http.Dir(WWWRootPath)
+	FileServer = http.FileServer(StaticFileSystem)
+	var err error
+	if ConfigData.CommonConfig.IsBackendProxyEnable {
+		ReverseProxyRemote, err = url.Parse(BackendTarget)
+		if err != nil {
+			emsg := fmt.Sprintf("Fatal Error! Backend Proxy URL Error: %s", err.Error())
+			ErrorLog.Emit(LogLv_FATAL, "Server", emsg)
+			fmt.Println(emsg)
+		}
+	}
+	ServerEngine.Any("/*reqpath", FrontendRouter)
+	ErrorLog.Emit(LogLv_INFO, "Server", "Start Listening...")
+	err = ServerEngine.Run(ListenAddress)
+	if err != nil {
+		emsg := fmt.Sprintf("Fatal Error! Server Couldn't Start: %s", err.Error())
+		ErrorLog.Emit(LogLv_FATAL, "Server", emsg)
+		fmt.Println(emsg)
+	}
+	ErrorLog.Emit(LogLv_INFO, "Server", "Server Ready.")
+}
+
+func FrontendRouter(ctx *gin.Context) {
+	rpath := ctx.Param("reqpath")
+	if strings.HasPrefix(rpath, "/"+BackendPrefix) {
+		APIReverseProxy(ctx)
+	} else {
+		StaticFilesHandler(rpath, ctx)
+	}
+}
+
+func NotFoundHandler(ctx *gin.Context) {
+	if ConfigData.CommonConfig.RedirectWhen404 {
+		ctx.Redirect(302, ConfigData.CommonConfig.RedirectURL)
+	} else {
+		ctx.Writer.WriteString("404 not found")
+		ctx.Status(404)
+	}
+}
+
+func ForbiddenHandler(ctx *gin.Context) {
+	ctx.Writer.WriteString("403 forbidden")
+	ctx.Status(403)
+}
+
+func StaticFilesHandler(url string, ctx *gin.Context) {
+	finf, err := StaticFileSystem.Open(path.Clean(url))
+	if os.IsNotExist(err) {
+		NotFoundHandler(ctx)
+		return
+	}
+	fst, err := finf.Stat()
+	if err != nil {
+		NotFoundHandler(ctx)
+		return
+	}
+	if fst.IsDir() {
+		_, err := StaticFileSystem.Open(path.Clean(path.Join(url, "index.html")))
+		if os.IsNotExist(err) {
+			ForbiddenHandler(ctx)
+			return
+		}
+	}
+	ctx.Request.URL.Path = url
+	FileServer.ServeHTTP(ctx.Writer, ctx.Request)
+}
+
+func APIReverseProxy(context *gin.Context) {
+	if !ConfigData.CommonConfig.IsBackendProxyEnable {
+		NotFoundHandler(context)
+	}
+	if context.IsWebsocket() {
+		proxy := wsutil.NewSingleHostReverseProxy(ReverseProxyRemote)
+		proxy.ServeHTTP(context.Writer, context.Request)
+	} else {
+		proxy := httputil.NewSingleHostReverseProxy(ReverseProxyRemote)
+		proxy.ServeHTTP(context.Writer, context.Request)
+	}
 }

+ 15 - 4
defaultFrontend/yamldef.go

@@ -1,14 +1,22 @@
 package main
 
 type FrontendConfigYAML struct {
-	LogConfig LogConfigYAML `yaml:"log"`
+	CommonConfig CommonConfigYAML `yaml:"common"`
+	LogConfig    LogConfigYAML    `yaml:"log"`
+}
+
+type CommonConfigYAML struct {
+	IsDebugModeOn        bool   `yaml:"debug"`
+	RedirectWhen404      bool   `yaml:"redirect_when_404"`
+	RedirectURL          string `yaml:"redirect_url"`
+	IsBackendProxyEnable bool   `yaml:"backend_proxy_enable"`
 }
 
 type LogConfigYAML struct {
 	AccessLogEnable          bool                    `yaml:"access_log_enable"`
-	RollingLogConfig         RollingLoggerConfigYAML `yaml:"rolling_logger_config"`
-	AccessLoggerDetailConfig AccessLoggerConfigYAML  `yaml:"access_logger_config"`
-	ErrorLoggerDetailConfig  ErrorLoggerConfigYAML   `yaml:"error_logger_config"`
+	RollingLogConfig         RollingLoggerConfigYAML `yaml:"rolling_log_config"`
+	AccessLoggerDetailConfig AccessLoggerConfigYAML  `yaml:"access_log_config"`
+	ErrorLoggerDetailConfig  ErrorLoggerConfigYAML   `yaml:"error_log_config"`
 }
 
 type RollingLoggerConfigYAML struct {
@@ -32,10 +40,13 @@ type AccessLoggerConfigYAML struct {
 	ForbiddenLevel     string `yaml:"forbidden_level"`
 	GatewayErrorLevel  string `yaml:"gateway_error_level"`
 	InternalErrorLevel string `yaml:"internal_error_level"`
+	OtherStatusLevel   string `yaml:"other_status_level"`
 	LogFormat          string `yaml:"log_format"`
+	UseUTC             bool   `yame:"use_utc"`
 }
 
 type ErrorLoggerConfigYAML struct {
 	OutputLevel string `yaml:"output_level"`
 	LogFormat   string `yaml:"log_format"`
+	UseUTC      bool   `yame:"use_utc"`
 }

+ 3 - 0
dist/Dockerfile

@@ -1,5 +1,8 @@
 FROM alpine
 COPY ./zDWSILauncher_linux /zDWSILauncher
 COPY ./rel /rel
+COPY ./data /data
+RUN chmod 755 /zDWSILauncher
+VOLUME ["/data"]
 EXPOSE 8080
 ENTRYPOINT /zDWSILauncher

+ 8 - 8
dist/rel/config.default.yaml

@@ -38,23 +38,23 @@ frontend:
 # config for backend
 backend:
   # 'true' for enable backend startup, 'false' for disable.
-  enable: false,
+  enable: true
   # absolute path to the backend executable file
-  entry: "/data/backend/Backend",
+  entry: "/data/backend/Backend"
   # listening address
   # (will set environment variable 'listen' when startup backend)
-  listen: ":9090",
+  listen: ":9090"
   # config for logger of backend startup shell
   shell_log":
     # absolute path to shell log (log rotating will append infix into filename)
-    file: "/data/logs/backend.shell.log",
+    file: "/data/logs/backend.shell.log"
     # max size per log file (MegaBytes)
-    max_size: 16,
+    max_size: 16
     # max days for rotating
-    max_age: 30,
+    max_age: 30
     # max backups for rotating remain
-    max_backups: 50,
+    max_backups: 50
     # 'true' for using local time for rotating
-    use_local_time: true,
+    use_local_time: true
     # 'true' for compress rotating history into zip files
     compress_history: true

BIN
dist/rel/zDWSIBlankBackend_linux


BIN
dist/rel/zDWSIFrontend_linux


+ 24 - 10
dist/rel/zdwsi.frontend.config.default.yaml

@@ -1,7 +1,17 @@
+# common config
+common:
+  # 'true' for enable global debug mode, 'false' for production environment
+  debug: true
+  # 'true' for redirect to 'redirect_url' when file not found, 'false' to return 404 message.
+  redirect_when_404: true
+  # when 'redirect_when_404' is 'true', it will redirect to this url when file not found.
+  redirect_url: "/"
+  # 'true' for enable backend reverse proxy, 'false' for disable.
+  backend_proxy_enable: true
 # config for log
 log:
   # 'true' for enable access log, 'false' for disable access log
-  access_log_enable: true,
+  access_log_enable: true
   # config for log rolling
   rolling_log_config:
     # config for error log rolling
@@ -33,7 +43,7 @@ log:
       # 'true' for compress rotating history into zip files
       compress_history: true
   # detail config for access log
-  error_logger_config:
+  error_log_config:
     # the log emitting level, the message which level below this will be emitted
     # optional value: 'DEBUG', 'INFO', 'WARN', 'ERROR', 'PANIC', 'FATAL'
     # all level option below should be one of these values
@@ -41,9 +51,12 @@ log:
     # format string for log. this formation using YAGTF.
     # Reference: http://git.swzry.com/zry/YAGTF
     # Expanded Tags: <level>, <unit>, <msg>
-    log_format: "[!<y>-<mon>-<d> <h24>:<min>:<s>.<us> <tz> <tzA>] <lt><level><gt>{<unit>} <msg><br>"
+    # Example: "![<y>-<mon>-<d> <h24>:<min>:<s>.<us> <tz> <tzA>] <lt><level><gt> {<unit>} <msg><br>"
+    log_format: "![<y>-<mon>-<d> <h24>:<min>:<s>.<us> <tz> <tzA>] <lt><level><gt> {<unit>} <msg><br>"
+    # 'true' for use UTC time in log, 'false' for use local timezone.
+    use_utc: false
   # detail config for access log
-  access_logger_config:
+  access_log_config:
     # the log emitting level, the message which level below this will be emitted
     # optional value: 'DEBUG', 'INFO', 'WARN', 'ERROR', 'PANIC', 'FATAL'
     # all level option below should be one of these values
@@ -58,14 +71,15 @@ log:
     gateway_error_level: "ERROR"
     # level for HTTP 500
     internal_error_level: "ERROR"
-    # level for logging before response
-    prelog_level: "DEBUG"
+    # level for Other HTTP Status Code
+    other_status_level: "INFO"
     # format string for log. this formation using YAGTF.
     # Reference: http://git.swzry.com/zry/YAGTF
     # Expanded Tags: <level>, <url>, <status>
-    # Example: "{<q>time<q>: <q>!<y>-<mon>-<d> <h24>:<min>:<s>.<us> <tz> <tzA><q>, <q>level<q>: <q><level><q>, <q>status<q>: <status>, <q>url<q>: <q><url><q>}<br>"
-    # Output example for this example: {"time": "2019-09-19 11:45:14.191981000 +0800 CST", "level": "INFO", "status": 200, "url": "/"}
-    log_format: "{<q>time<q>: <q>!<y>-<mon>-<d> <h24>:<min>:<s>.<us> <tz> <tzA><q>, <q>level<q>: <q><level><q>, <q>status<q>: <status>, <q>url<q>: <q><url><q>}<br>"
-
+    # Example: "!{<q>time<q>: <q><y>-<mon>-<d> <h24>:<min>:<s>.<us> <tz> <tzA><q>, <q>level<q>: <q><level><q>, <q>method<q>: <q><method><q>, <q>status<q>: <status>, <q>client_ip<q>: <q><cip><q>, <q>url<q>: <q><url><q>}<br>"
+    # Output example for this example: {"time": "2019-09-19 11:45:14.191981000 +0800 CST", "level": "INFO", "method": "GET", "status": 200, "client_ip": "127.0.0.1", "url": "/"}
+    log_format: "!{<q>time<q>: <q><y>-<mon>-<d> <h24>:<min>:<s>.<us> <tz> <tzA><q>, <q>level<q>: <q><level><q>, <q>method<q>: <q><method><q>, <q>status<q>: <status>, <q>client_ip<q>: <q><cip><q>, <q>url<q>: <q><url><q>}<br>"
+    # 'true' for use UTC time in log, 'false' for use local timezone.
+    use_utc: false
 
 

BIN
dist/zDWSILauncher_linux


+ 4 - 0
launcher/main.go

@@ -7,6 +7,7 @@ import (
 	"gopkg.in/yaml.v2"
 	"io"
 	"io/ioutil"
+	"os"
 	"os/exec"
 	"sync"
 )
@@ -39,7 +40,10 @@ func CheckInit() {
 	pathutils.CopyFile("/data/config.yaml", "/rel/config.default.yaml")
 	pathutils.CopyFile("/data/wwwroot/index.html", "/rel/index.default.html")
 	pathutils.CopyFile("/data/frontend/zDWSIFrontend", "/rel/zDWSIFrontend_linux")
+	pathutils.CopyFile("/data/backend/Backend", "/rel/zDWSIBlankBackend_linux")
 	pathutils.CopyFile("/data/frontend/zdwsi.frontend.config.yaml", "/rel/zdwsi.frontend.config.default.yaml")
+	os.Chmod("/data/frontend/zDWSIFrontend", 0755)
+	os.Chmod("/data/backend/Backend", 0755)
 	fmt.Println("Container Initialized. Please Edit 'config.yaml'.")
 }