Pause, Resume, Release&Reopen, Add and Remove Logging from command line (#11777)
* Make LogDescriptions race safe * Add manager commands for pausing, resuming, adding and removing loggers Signed-off-by: Andrew Thornton <art27@cantab.net> * Placate lint * Ensure that file logger is run! * Add support for smtp and conn Signed-off-by: Andrew Thornton <art27@cantab.net> * Add release-and-reopen Signed-off-by: Andrew Thornton <art27@cantab.net> Co-authored-by: techknowlogick <techknowlogick@gitea.io> Co-authored-by: Lauris BH <lauris@nix.lv>
This commit is contained in:
		
					parent
					
						
							
								38fb087d19
							
						
					
				
			
			
				commit
				
					
						c5b08f6d5a
					
				
			
		
					 17 changed files with 924 additions and 17 deletions
				
			
		
							
								
								
									
										372
									
								
								cmd/manager.go
									
										
									
									
									
								
							
							
						
						
									
										372
									
								
								cmd/manager.go
									
										
									
									
									
								
							| 
						 | 
					@ -10,6 +10,7 @@ import (
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/private"
 | 
						"code.gitea.io/gitea/modules/private"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
| 
						 | 
					@ -25,16 +26,27 @@ var (
 | 
				
			||||||
			subcmdShutdown,
 | 
								subcmdShutdown,
 | 
				
			||||||
			subcmdRestart,
 | 
								subcmdRestart,
 | 
				
			||||||
			subcmdFlushQueues,
 | 
								subcmdFlushQueues,
 | 
				
			||||||
 | 
								subcmdLogging,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	subcmdShutdown = cli.Command{
 | 
						subcmdShutdown = cli.Command{
 | 
				
			||||||
		Name:  "shutdown",
 | 
							Name:  "shutdown",
 | 
				
			||||||
		Usage: "Gracefully shutdown the running process",
 | 
							Usage: "Gracefully shutdown the running process",
 | 
				
			||||||
 | 
							Flags: []cli.Flag{
 | 
				
			||||||
 | 
								cli.BoolFlag{
 | 
				
			||||||
 | 
									Name: "debug",
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
		Action: runShutdown,
 | 
							Action: runShutdown,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	subcmdRestart = cli.Command{
 | 
						subcmdRestart = cli.Command{
 | 
				
			||||||
		Name:  "restart",
 | 
							Name:  "restart",
 | 
				
			||||||
		Usage: "Gracefully restart the running process - (not implemented for windows servers)",
 | 
							Usage: "Gracefully restart the running process - (not implemented for windows servers)",
 | 
				
			||||||
 | 
							Flags: []cli.Flag{
 | 
				
			||||||
 | 
								cli.BoolFlag{
 | 
				
			||||||
 | 
									Name: "debug",
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
		Action: runRestart,
 | 
							Action: runRestart,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	subcmdFlushQueues = cli.Command{
 | 
						subcmdFlushQueues = cli.Command{
 | 
				
			||||||
| 
						 | 
					@ -46,17 +58,331 @@ var (
 | 
				
			||||||
				Name:  "timeout",
 | 
									Name:  "timeout",
 | 
				
			||||||
				Value: 60 * time.Second,
 | 
									Value: 60 * time.Second,
 | 
				
			||||||
				Usage: "Timeout for the flushing process",
 | 
									Usage: "Timeout for the flushing process",
 | 
				
			||||||
			},
 | 
								}, cli.BoolFlag{
 | 
				
			||||||
			cli.BoolFlag{
 | 
					 | 
				
			||||||
				Name:  "non-blocking",
 | 
									Name:  "non-blocking",
 | 
				
			||||||
				Usage: "Set to true to not wait for flush to complete before returning",
 | 
									Usage: "Set to true to not wait for flush to complete before returning",
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
 | 
								cli.BoolFlag{
 | 
				
			||||||
 | 
									Name: "debug",
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defaultLoggingFlags = []cli.Flag{
 | 
				
			||||||
 | 
							cli.StringFlag{
 | 
				
			||||||
 | 
								Name:  "group, g",
 | 
				
			||||||
 | 
								Usage: "Group to add logger to - will default to \"default\"",
 | 
				
			||||||
 | 
							}, cli.StringFlag{
 | 
				
			||||||
 | 
								Name:  "name, n",
 | 
				
			||||||
 | 
								Usage: "Name of the new logger - will default to mode",
 | 
				
			||||||
 | 
							}, cli.StringFlag{
 | 
				
			||||||
 | 
								Name:  "level, l",
 | 
				
			||||||
 | 
								Usage: "Logging level for the new logger",
 | 
				
			||||||
 | 
							}, cli.StringFlag{
 | 
				
			||||||
 | 
								Name:  "stacktrace-level, L",
 | 
				
			||||||
 | 
								Usage: "Stacktrace logging level",
 | 
				
			||||||
 | 
							}, cli.StringFlag{
 | 
				
			||||||
 | 
								Name:  "flags, F",
 | 
				
			||||||
 | 
								Usage: "Flags for the logger",
 | 
				
			||||||
 | 
							}, cli.StringFlag{
 | 
				
			||||||
 | 
								Name:  "expression, e",
 | 
				
			||||||
 | 
								Usage: "Matching expression for the logger",
 | 
				
			||||||
 | 
							}, cli.StringFlag{
 | 
				
			||||||
 | 
								Name:  "prefix, p",
 | 
				
			||||||
 | 
								Usage: "Prefix for the logger",
 | 
				
			||||||
 | 
							}, cli.BoolFlag{
 | 
				
			||||||
 | 
								Name:  "color",
 | 
				
			||||||
 | 
								Usage: "Use color in the logs",
 | 
				
			||||||
 | 
							}, cli.BoolFlag{
 | 
				
			||||||
 | 
								Name: "debug",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						subcmdLogging = cli.Command{
 | 
				
			||||||
 | 
							Name:  "logging",
 | 
				
			||||||
 | 
							Usage: "Adjust logging commands",
 | 
				
			||||||
 | 
							Subcommands: []cli.Command{
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									Name:  "pause",
 | 
				
			||||||
 | 
									Usage: "Pause logging (Gitea will buffer logs up to a certain point and will drop them after that point)",
 | 
				
			||||||
 | 
									Flags: []cli.Flag{
 | 
				
			||||||
 | 
										cli.BoolFlag{
 | 
				
			||||||
 | 
											Name: "debug",
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Action: runPauseLogging,
 | 
				
			||||||
 | 
								}, {
 | 
				
			||||||
 | 
									Name:  "resume",
 | 
				
			||||||
 | 
									Usage: "Resume logging",
 | 
				
			||||||
 | 
									Flags: []cli.Flag{
 | 
				
			||||||
 | 
										cli.BoolFlag{
 | 
				
			||||||
 | 
											Name: "debug",
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Action: runResumeLogging,
 | 
				
			||||||
 | 
								}, {
 | 
				
			||||||
 | 
									Name:  "release-and-reopen",
 | 
				
			||||||
 | 
									Usage: "Cause Gitea to release and re-open files used for logging",
 | 
				
			||||||
 | 
									Flags: []cli.Flag{
 | 
				
			||||||
 | 
										cli.BoolFlag{
 | 
				
			||||||
 | 
											Name: "debug",
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Action: runReleaseReopenLogging,
 | 
				
			||||||
 | 
								}, {
 | 
				
			||||||
 | 
									Name:      "remove",
 | 
				
			||||||
 | 
									Usage:     "Remove a logger",
 | 
				
			||||||
 | 
									ArgsUsage: "[name] Name of logger to remove",
 | 
				
			||||||
 | 
									Flags: []cli.Flag{
 | 
				
			||||||
 | 
										cli.BoolFlag{
 | 
				
			||||||
 | 
											Name: "debug",
 | 
				
			||||||
 | 
										}, cli.StringFlag{
 | 
				
			||||||
 | 
											Name:  "group, g",
 | 
				
			||||||
 | 
											Usage: "Group to add logger to - will default to \"default\"",
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Action: runRemoveLogger,
 | 
				
			||||||
 | 
								}, {
 | 
				
			||||||
 | 
									Name:  "add",
 | 
				
			||||||
 | 
									Usage: "Add a logger",
 | 
				
			||||||
 | 
									Subcommands: []cli.Command{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											Name:  "console",
 | 
				
			||||||
 | 
											Usage: "Add a console logger",
 | 
				
			||||||
 | 
											Flags: append(defaultLoggingFlags,
 | 
				
			||||||
 | 
												cli.BoolFlag{
 | 
				
			||||||
 | 
													Name:  "stderr",
 | 
				
			||||||
 | 
													Usage: "Output console logs to stderr - only relevant for console",
 | 
				
			||||||
 | 
												}),
 | 
				
			||||||
 | 
											Action: runAddConsoleLogger,
 | 
				
			||||||
 | 
										}, {
 | 
				
			||||||
 | 
											Name:  "file",
 | 
				
			||||||
 | 
											Usage: "Add a file logger",
 | 
				
			||||||
 | 
											Flags: append(defaultLoggingFlags, []cli.Flag{
 | 
				
			||||||
 | 
												cli.StringFlag{
 | 
				
			||||||
 | 
													Name:  "filename, f",
 | 
				
			||||||
 | 
													Usage: "Filename for the logger - this must be set.",
 | 
				
			||||||
 | 
												}, cli.BoolTFlag{
 | 
				
			||||||
 | 
													Name:  "rotate, r",
 | 
				
			||||||
 | 
													Usage: "Rotate logs",
 | 
				
			||||||
 | 
												}, cli.Int64Flag{
 | 
				
			||||||
 | 
													Name:  "max-size, s",
 | 
				
			||||||
 | 
													Usage: "Maximum size in bytes before rotation",
 | 
				
			||||||
 | 
												}, cli.BoolTFlag{
 | 
				
			||||||
 | 
													Name:  "daily, d",
 | 
				
			||||||
 | 
													Usage: "Rotate logs daily",
 | 
				
			||||||
 | 
												}, cli.IntFlag{
 | 
				
			||||||
 | 
													Name:  "max-days, D",
 | 
				
			||||||
 | 
													Usage: "Maximum number of daily logs to keep",
 | 
				
			||||||
 | 
												}, cli.BoolTFlag{
 | 
				
			||||||
 | 
													Name:  "compress, z",
 | 
				
			||||||
 | 
													Usage: "Compress rotated logs",
 | 
				
			||||||
 | 
												}, cli.IntFlag{
 | 
				
			||||||
 | 
													Name:  "compression-level, Z",
 | 
				
			||||||
 | 
													Usage: "Compression level to use",
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											}...),
 | 
				
			||||||
 | 
											Action: runAddFileLogger,
 | 
				
			||||||
 | 
										}, {
 | 
				
			||||||
 | 
											Name:  "conn",
 | 
				
			||||||
 | 
											Usage: "Add a net conn logger",
 | 
				
			||||||
 | 
											Flags: append(defaultLoggingFlags, []cli.Flag{
 | 
				
			||||||
 | 
												cli.BoolFlag{
 | 
				
			||||||
 | 
													Name:  "reconnect-on-message, R",
 | 
				
			||||||
 | 
													Usage: "Reconnect to host for every message",
 | 
				
			||||||
 | 
												}, cli.BoolFlag{
 | 
				
			||||||
 | 
													Name:  "reconnect, r",
 | 
				
			||||||
 | 
													Usage: "Reconnect to host when connection is dropped",
 | 
				
			||||||
 | 
												}, cli.StringFlag{
 | 
				
			||||||
 | 
													Name:  "protocol, P",
 | 
				
			||||||
 | 
													Usage: "Set protocol to use: tcp, unix, or udp (defaults to tcp)",
 | 
				
			||||||
 | 
												}, cli.StringFlag{
 | 
				
			||||||
 | 
													Name:  "address, a",
 | 
				
			||||||
 | 
													Usage: "Host address and port to connect to (defaults to :7020)",
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											}...),
 | 
				
			||||||
 | 
											Action: runAddConnLogger,
 | 
				
			||||||
 | 
										}, {
 | 
				
			||||||
 | 
											Name:  "smtp",
 | 
				
			||||||
 | 
											Usage: "Add an SMTP logger",
 | 
				
			||||||
 | 
											Flags: append(defaultLoggingFlags, []cli.Flag{
 | 
				
			||||||
 | 
												cli.StringFlag{
 | 
				
			||||||
 | 
													Name:  "username, u",
 | 
				
			||||||
 | 
													Usage: "Mail server username",
 | 
				
			||||||
 | 
												}, cli.StringFlag{
 | 
				
			||||||
 | 
													Name:  "password, P",
 | 
				
			||||||
 | 
													Usage: "Mail server password",
 | 
				
			||||||
 | 
												}, cli.StringFlag{
 | 
				
			||||||
 | 
													Name:  "host, H",
 | 
				
			||||||
 | 
													Usage: "Mail server host (defaults to: 127.0.0.1:25)",
 | 
				
			||||||
 | 
												}, cli.StringSliceFlag{
 | 
				
			||||||
 | 
													Name:  "send-to, s",
 | 
				
			||||||
 | 
													Usage: "Email address(es) to send to",
 | 
				
			||||||
 | 
												}, cli.StringFlag{
 | 
				
			||||||
 | 
													Name:  "subject, S",
 | 
				
			||||||
 | 
													Usage: "Subject header of sent emails",
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											}...),
 | 
				
			||||||
 | 
											Action: runAddSMTPLogger,
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func runRemoveLogger(c *cli.Context) error {
 | 
				
			||||||
 | 
						setup("manager", c.Bool("debug"))
 | 
				
			||||||
 | 
						group := c.String("group")
 | 
				
			||||||
 | 
						if len(group) == 0 {
 | 
				
			||||||
 | 
							group = log.DEFAULT
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						name := c.Args().First()
 | 
				
			||||||
 | 
						statusCode, msg := private.RemoveLogger(group, name)
 | 
				
			||||||
 | 
						switch statusCode {
 | 
				
			||||||
 | 
						case http.StatusInternalServerError:
 | 
				
			||||||
 | 
							fail("InternalServerError", msg)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fmt.Fprintln(os.Stdout, msg)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func runAddSMTPLogger(c *cli.Context) error {
 | 
				
			||||||
 | 
						setup("manager", c.Bool("debug"))
 | 
				
			||||||
 | 
						vals := map[string]interface{}{}
 | 
				
			||||||
 | 
						mode := "smtp"
 | 
				
			||||||
 | 
						if c.IsSet("host") {
 | 
				
			||||||
 | 
							vals["host"] = c.String("host")
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							vals["host"] = "127.0.0.1:25"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if c.IsSet("username") {
 | 
				
			||||||
 | 
							vals["username"] = c.String("username")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if c.IsSet("password") {
 | 
				
			||||||
 | 
							vals["password"] = c.String("password")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !c.IsSet("send-to") {
 | 
				
			||||||
 | 
							return fmt.Errorf("Some recipients must be provided")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						vals["sendTos"] = c.StringSlice("send-to")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if c.IsSet("subject") {
 | 
				
			||||||
 | 
							vals["subject"] = c.String("subject")
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							vals["subject"] = "Diagnostic message from Gitea"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return commonAddLogger(c, mode, vals)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func runAddConnLogger(c *cli.Context) error {
 | 
				
			||||||
 | 
						setup("manager", c.Bool("debug"))
 | 
				
			||||||
 | 
						vals := map[string]interface{}{}
 | 
				
			||||||
 | 
						mode := "conn"
 | 
				
			||||||
 | 
						vals["net"] = "tcp"
 | 
				
			||||||
 | 
						if c.IsSet("protocol") {
 | 
				
			||||||
 | 
							switch c.String("protocol") {
 | 
				
			||||||
 | 
							case "udp":
 | 
				
			||||||
 | 
								vals["net"] = "udp"
 | 
				
			||||||
 | 
							case "unix":
 | 
				
			||||||
 | 
								vals["net"] = "unix"
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if c.IsSet("address") {
 | 
				
			||||||
 | 
							vals["address"] = c.String("address")
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							vals["address"] = ":7020"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if c.IsSet("reconnect") {
 | 
				
			||||||
 | 
							vals["reconnect"] = c.Bool("reconnect")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if c.IsSet("reconnect-on-message") {
 | 
				
			||||||
 | 
							vals["reconnectOnMsg"] = c.Bool("reconnect-on-message")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return commonAddLogger(c, mode, vals)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func runAddFileLogger(c *cli.Context) error {
 | 
				
			||||||
 | 
						setup("manager", c.Bool("debug"))
 | 
				
			||||||
 | 
						vals := map[string]interface{}{}
 | 
				
			||||||
 | 
						mode := "file"
 | 
				
			||||||
 | 
						if c.IsSet("filename") {
 | 
				
			||||||
 | 
							vals["filename"] = c.String("filename")
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							return fmt.Errorf("filename must be set when creating a file logger")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if c.IsSet("rotate") {
 | 
				
			||||||
 | 
							vals["rotate"] = c.Bool("rotate")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if c.IsSet("max-size") {
 | 
				
			||||||
 | 
							vals["maxsize"] = c.Int64("max-size")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if c.IsSet("daily") {
 | 
				
			||||||
 | 
							vals["daily"] = c.Bool("daily")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if c.IsSet("max-days") {
 | 
				
			||||||
 | 
							vals["maxdays"] = c.Int("max-days")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if c.IsSet("compress") {
 | 
				
			||||||
 | 
							vals["compress"] = c.Bool("compress")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if c.IsSet("compression-level") {
 | 
				
			||||||
 | 
							vals["compressionLevel"] = c.Int("compression-level")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return commonAddLogger(c, mode, vals)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func runAddConsoleLogger(c *cli.Context) error {
 | 
				
			||||||
 | 
						setup("manager", c.Bool("debug"))
 | 
				
			||||||
 | 
						vals := map[string]interface{}{}
 | 
				
			||||||
 | 
						mode := "console"
 | 
				
			||||||
 | 
						if c.IsSet("stderr") && c.Bool("stderr") {
 | 
				
			||||||
 | 
							vals["stderr"] = c.Bool("stderr")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return commonAddLogger(c, mode, vals)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func commonAddLogger(c *cli.Context, mode string, vals map[string]interface{}) error {
 | 
				
			||||||
 | 
						if len(c.String("level")) > 0 {
 | 
				
			||||||
 | 
							vals["level"] = log.FromString(c.String("level")).String()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if len(c.String("stacktrace-level")) > 0 {
 | 
				
			||||||
 | 
							vals["stacktraceLevel"] = log.FromString(c.String("stacktrace-level")).String()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if len(c.String("expression")) > 0 {
 | 
				
			||||||
 | 
							vals["expression"] = c.String("expression")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if len(c.String("prefix")) > 0 {
 | 
				
			||||||
 | 
							vals["prefix"] = c.String("prefix")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if len(c.String("flags")) > 0 {
 | 
				
			||||||
 | 
							vals["flags"] = log.FlagsFromString(c.String("flags"))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if c.IsSet("color") {
 | 
				
			||||||
 | 
							vals["colorize"] = c.Bool("color")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						group := "default"
 | 
				
			||||||
 | 
						if c.IsSet("group") {
 | 
				
			||||||
 | 
							group = c.String("group")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						name := mode
 | 
				
			||||||
 | 
						if c.IsSet("name") {
 | 
				
			||||||
 | 
							name = c.String("name")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						statusCode, msg := private.AddLogger(group, name, mode, vals)
 | 
				
			||||||
 | 
						switch statusCode {
 | 
				
			||||||
 | 
						case http.StatusInternalServerError:
 | 
				
			||||||
 | 
							fail("InternalServerError", msg)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fmt.Fprintln(os.Stdout, msg)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func runShutdown(c *cli.Context) error {
 | 
					func runShutdown(c *cli.Context) error {
 | 
				
			||||||
	setup("manager", false)
 | 
						setup("manager", c.Bool("debug"))
 | 
				
			||||||
	statusCode, msg := private.Shutdown()
 | 
						statusCode, msg := private.Shutdown()
 | 
				
			||||||
	switch statusCode {
 | 
						switch statusCode {
 | 
				
			||||||
	case http.StatusInternalServerError:
 | 
						case http.StatusInternalServerError:
 | 
				
			||||||
| 
						 | 
					@ -68,7 +394,7 @@ func runShutdown(c *cli.Context) error {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func runRestart(c *cli.Context) error {
 | 
					func runRestart(c *cli.Context) error {
 | 
				
			||||||
	setup("manager", false)
 | 
						setup("manager", c.Bool("debug"))
 | 
				
			||||||
	statusCode, msg := private.Restart()
 | 
						statusCode, msg := private.Restart()
 | 
				
			||||||
	switch statusCode {
 | 
						switch statusCode {
 | 
				
			||||||
	case http.StatusInternalServerError:
 | 
						case http.StatusInternalServerError:
 | 
				
			||||||
| 
						 | 
					@ -80,7 +406,7 @@ func runRestart(c *cli.Context) error {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func runFlushQueues(c *cli.Context) error {
 | 
					func runFlushQueues(c *cli.Context) error {
 | 
				
			||||||
	setup("manager", false)
 | 
						setup("manager", c.Bool("debug"))
 | 
				
			||||||
	statusCode, msg := private.FlushQueues(c.Duration("timeout"), c.Bool("non-blocking"))
 | 
						statusCode, msg := private.FlushQueues(c.Duration("timeout"), c.Bool("non-blocking"))
 | 
				
			||||||
	switch statusCode {
 | 
						switch statusCode {
 | 
				
			||||||
	case http.StatusInternalServerError:
 | 
						case http.StatusInternalServerError:
 | 
				
			||||||
| 
						 | 
					@ -90,3 +416,39 @@ func runFlushQueues(c *cli.Context) error {
 | 
				
			||||||
	fmt.Fprintln(os.Stdout, msg)
 | 
						fmt.Fprintln(os.Stdout, msg)
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func runPauseLogging(c *cli.Context) error {
 | 
				
			||||||
 | 
						setup("manager", c.Bool("debug"))
 | 
				
			||||||
 | 
						statusCode, msg := private.PauseLogging()
 | 
				
			||||||
 | 
						switch statusCode {
 | 
				
			||||||
 | 
						case http.StatusInternalServerError:
 | 
				
			||||||
 | 
							fail("InternalServerError", msg)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fmt.Fprintln(os.Stdout, msg)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func runResumeLogging(c *cli.Context) error {
 | 
				
			||||||
 | 
						setup("manager", c.Bool("debug"))
 | 
				
			||||||
 | 
						statusCode, msg := private.ResumeLogging()
 | 
				
			||||||
 | 
						switch statusCode {
 | 
				
			||||||
 | 
						case http.StatusInternalServerError:
 | 
				
			||||||
 | 
							fail("InternalServerError", msg)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fmt.Fprintln(os.Stdout, msg)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func runReleaseReopenLogging(c *cli.Context) error {
 | 
				
			||||||
 | 
						setup("manager", c.Bool("debug"))
 | 
				
			||||||
 | 
						statusCode, msg := private.ReleaseReopenLogging()
 | 
				
			||||||
 | 
						switch statusCode {
 | 
				
			||||||
 | 
						case http.StatusInternalServerError:
 | 
				
			||||||
 | 
							fail("InternalServerError", msg)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fmt.Fprintln(os.Stdout, msg)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -316,6 +316,28 @@ COLORIZE = true # Or false if your windows terminal cannot color
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This is equivalent to sending all logs to the console, with default go log being sent to the console log too.
 | 
					This is equivalent to sending all logs to the console, with default go log being sent to the console log too.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Releasing-and-Reopening, Pausing and Resuming logging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you are running on Unix you may wish to release-and-reopen logs in order to use `logrotate` or other tools.
 | 
				
			||||||
 | 
					It is possible force gitea to release and reopen it's logging files and connections by sending `SIGUSR1` to the
 | 
				
			||||||
 | 
					running process, or running `gitea manager logging release-and-reopen`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Alternatively, you may wish to pause and resume logging - this can be accomplished through the use of the 
 | 
				
			||||||
 | 
					`gitea manager logging pause` and `gitea manager logging resume` commands. Please note that whilst logging
 | 
				
			||||||
 | 
					is paused log events below INFO level will not be stored and only a limited number of events will be stored.
 | 
				
			||||||
 | 
					Logging may block, albeit temporarily, slowing gitea considerably whilst paused - therefore it is
 | 
				
			||||||
 | 
					recommended that pausing only done for a very short period of time.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Adding and removing logging whilst Gitea is running
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					It is possible to add and remove logging whilst Gitea is running using the `gitea manager logging add` and `remove` subcommands.
 | 
				
			||||||
 | 
					This functionality can only adjust running log systems and cannot be used to start the access, macaron or router loggers if they
 | 
				
			||||||
 | 
					were not already initialised. If you wish to start these systems you are advised to adjust the app.ini and (gracefully) restart
 | 
				
			||||||
 | 
					the Gitea service.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The main intention of these commands is to easily add a temporary logger to investigate problems on running systems where a restart
 | 
				
			||||||
 | 
					may cause the issue to disappear.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Log colorization
 | 
					## Log colorization
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Logs to the console will be colorized by default when not running on
 | 
					Logs to the console will be colorized by default when not running on
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -318,3 +318,85 @@ var checklist = []check{
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This function will receive a command line context and return a list of details about the problems or error.
 | 
					This function will receive a command line context and return a list of details about the problems or error.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### manager
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Manage running server operations:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Commands:
 | 
				
			||||||
 | 
					  - `shutdown`:      Gracefully shutdown the running process
 | 
				
			||||||
 | 
					  - `restart`:       Gracefully restart the running process - (not implemented for windows servers)
 | 
				
			||||||
 | 
					  - `flush-queues`:  Flush queues in the running process
 | 
				
			||||||
 | 
					    - Options:
 | 
				
			||||||
 | 
					      - `--timeout value`: Timeout for the flushing process (default: 1m0s)
 | 
				
			||||||
 | 
					      - `--non-blocking`: Set to true to not wait for flush to complete before returning
 | 
				
			||||||
 | 
					  - `logging`:       Adjust logging commands
 | 
				
			||||||
 | 
					    - Commands:
 | 
				
			||||||
 | 
					      - `pause`:   Pause logging
 | 
				
			||||||
 | 
					        - Notes:
 | 
				
			||||||
 | 
					          - The logging level will be raised to INFO temporarily if it is below this level.
 | 
				
			||||||
 | 
					          - Gitea will buffer logs up to a certain point and will drop them after that point.
 | 
				
			||||||
 | 
					      - `resume`:  Resume logging
 | 
				
			||||||
 | 
					      - `release-and-reopen`: Cause Gitea to release and re-open files and connections used for logging (Equivalent to sending SIGUSR1 to Gitea.)
 | 
				
			||||||
 | 
					      - `remove name`: Remove the named logger
 | 
				
			||||||
 | 
					        - Options:
 | 
				
			||||||
 | 
					          - `--group group`, `-g group`: Set the group to remove the sublogger from. (defaults to `default`)
 | 
				
			||||||
 | 
					      - `add`:     Add a logger
 | 
				
			||||||
 | 
					        - Commands:
 | 
				
			||||||
 | 
					          - `console`: Add a console logger
 | 
				
			||||||
 | 
					            - Options:
 | 
				
			||||||
 | 
					              - `--group value`, `-g value`: Group to add logger to - will default to "default"
 | 
				
			||||||
 | 
					              - `--name value`, `-n value`: Name of the new logger - will default to mode
 | 
				
			||||||
 | 
					              - `--level value`, `-l value`: Logging level for the new logger
 | 
				
			||||||
 | 
					              - `--stacktrace-level value`, `-L value`: Stacktrace logging level
 | 
				
			||||||
 | 
					              - `--flags value`, `-F value`: Flags for the logger
 | 
				
			||||||
 | 
					              - `--expression value`, `-e value`: Matching expression for the logger
 | 
				
			||||||
 | 
					              - `--prefix value`, `-p value`: Prefix for the logger
 | 
				
			||||||
 | 
					              - `--color`: Use color in the logs
 | 
				
			||||||
 | 
					              - `--stderr`: Output console logs to stderr - only relevant for console
 | 
				
			||||||
 | 
					          - `file`: Add a file logger
 | 
				
			||||||
 | 
					            - Options:
 | 
				
			||||||
 | 
					              - `--group value`, `-g value`: Group to add logger to - will default to "default"
 | 
				
			||||||
 | 
					              - `--name value`, `-n value`:  Name of the new logger - will default to mode
 | 
				
			||||||
 | 
					              - `--level value`, `-l value`: Logging level for the new logger
 | 
				
			||||||
 | 
					              - `--stacktrace-level value`, `-L value`: Stacktrace logging level
 | 
				
			||||||
 | 
					              - `--flags value`, `-F value`: Flags for the logger
 | 
				
			||||||
 | 
					              - `--expression value`, `-e value`: Matching expression for the logger
 | 
				
			||||||
 | 
					              - `--prefix value`, `-p value`: Prefix for the logger
 | 
				
			||||||
 | 
					              - `--color`: Use color in the logs
 | 
				
			||||||
 | 
					              - `--filename value`, `-f value`: Filename for the logger - 
 | 
				
			||||||
 | 
					              - `--rotate`, `-r`: Rotate logs
 | 
				
			||||||
 | 
					              - `--max-size value`, `-s value`: Maximum size in bytes before rotation
 | 
				
			||||||
 | 
					              - `--daily`, `-d`: Rotate logs daily
 | 
				
			||||||
 | 
					              - `--max-days value`, `-D value`: Maximum number of daily logs to keep
 | 
				
			||||||
 | 
					              - `--compress`, `-z`: Compress rotated logs
 | 
				
			||||||
 | 
					              - `--compression-level value`, `-Z value`: Compression level to use
 | 
				
			||||||
 | 
					          - `conn`: Add a network connection logger
 | 
				
			||||||
 | 
					            - Options:
 | 
				
			||||||
 | 
					              - `--group value`, `-g value`: Group to add logger to - will default to "default"
 | 
				
			||||||
 | 
					              - `--name value`, `-n value`:  Name of the new logger - will default to mode
 | 
				
			||||||
 | 
					              - `--level value`, `-l value`: Logging level for the new logger
 | 
				
			||||||
 | 
					              - `--stacktrace-level value`, `-L value`: Stacktrace logging level
 | 
				
			||||||
 | 
					              - `--flags value`, `-F value`: Flags for the logger
 | 
				
			||||||
 | 
					              - `--expression value`, `-e value`: Matching expression for the logger
 | 
				
			||||||
 | 
					              - `--prefix value`, `-p value`: Prefix for the logger
 | 
				
			||||||
 | 
					              - `--color`: Use color in the logs
 | 
				
			||||||
 | 
					              - `--reconnect-on-message`, `-R`: Reconnect to host for every message
 | 
				
			||||||
 | 
					              - `--reconnect`, `-r`: Reconnect to host when connection is dropped
 | 
				
			||||||
 | 
					              - `--protocol value`, `-P value`: Set protocol to use: tcp, unix, or udp (defaults to tcp)
 | 
				
			||||||
 | 
					              - `--address value`, `-a value`: Host address and port to connect to (defaults to :7020)
 | 
				
			||||||
 | 
					          - `smtp`: Add an SMTP logger
 | 
				
			||||||
 | 
					            - Options:
 | 
				
			||||||
 | 
					              - `--group value`, `-g value`: Group to add logger to - will default to "default"
 | 
				
			||||||
 | 
					              - `--name value`, `-n value`: Name of the new logger - will default to mode
 | 
				
			||||||
 | 
					              - `--level value`, `-l value`: Logging level for the new logger
 | 
				
			||||||
 | 
					              - `--stacktrace-level value`, `-L value`: Stacktrace logging level
 | 
				
			||||||
 | 
					              - `--flags value`, `-F value`: Flags for the logger
 | 
				
			||||||
 | 
					              - `--expression value`, `-e value`: Matching expression for the logger
 | 
				
			||||||
 | 
					              - `--prefix value`, `-p value`: Prefix for the logger
 | 
				
			||||||
 | 
					              - `--color`: Use color in the logs
 | 
				
			||||||
 | 
					              - `--username value`, `-u value`: Mail server username
 | 
				
			||||||
 | 
					              - `--password value`, `-P value`: Mail server password
 | 
				
			||||||
 | 
					              - `--host value`, `-H value`: Mail server host (defaults to: 127.0.0.1:25)
 | 
				
			||||||
 | 
					              - `--send-to value`, `-s value`: Email address(es) to send to
 | 
				
			||||||
 | 
					              - `--subject value`, `-S value`: Subject header of sent emails
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -170,6 +170,11 @@ func (log *TestLogger) Init(config string) error {
 | 
				
			||||||
func (log *TestLogger) Flush() {
 | 
					func (log *TestLogger) Flush() {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//ReleaseReopen does nothing
 | 
				
			||||||
 | 
					func (log *TestLogger) ReleaseReopen() error {
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetName returns the default name for this implementation
 | 
					// GetName returns the default name for this implementation
 | 
				
			||||||
func (log *TestLogger) GetName() string {
 | 
					func (log *TestLogger) GetName() string {
 | 
				
			||||||
	return "test"
 | 
						return "test"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -113,7 +113,10 @@ func (g *Manager) handleSignals(ctx context.Context) {
 | 
				
			||||||
				log.Info("PID: %d. Received SIGHUP. Attempting GracefulRestart...", pid)
 | 
									log.Info("PID: %d. Received SIGHUP. Attempting GracefulRestart...", pid)
 | 
				
			||||||
				g.DoGracefulRestart()
 | 
									g.DoGracefulRestart()
 | 
				
			||||||
			case syscall.SIGUSR1:
 | 
								case syscall.SIGUSR1:
 | 
				
			||||||
				log.Info("PID %d. Received SIGUSR1.", pid)
 | 
									log.Warn("PID %d. Received SIGUSR1. Releasing and reopening logs", pid)
 | 
				
			||||||
 | 
									if err := log.ReleaseReopen(); err != nil {
 | 
				
			||||||
 | 
										log.Error("Error whilst releasing and reopening logs: %v", err)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			case syscall.SIGUSR2:
 | 
								case syscall.SIGUSR2:
 | 
				
			||||||
				log.Warn("PID %d. Received SIGUSR2. Hammering...", pid)
 | 
									log.Warn("PID %d. Received SIGUSR2. Hammering...", pid)
 | 
				
			||||||
				g.DoImmediateHammer()
 | 
									g.DoImmediateHammer()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -77,6 +77,13 @@ func (i *connWriter) connect() error {
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (i *connWriter) releaseReopen() error {
 | 
				
			||||||
 | 
						if i.innerWriter != nil {
 | 
				
			||||||
 | 
							return i.connect()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ConnLogger implements LoggerProvider.
 | 
					// ConnLogger implements LoggerProvider.
 | 
				
			||||||
// it writes messages in keep-live tcp connection.
 | 
					// it writes messages in keep-live tcp connection.
 | 
				
			||||||
type ConnLogger struct {
 | 
					type ConnLogger struct {
 | 
				
			||||||
| 
						 | 
					@ -119,6 +126,11 @@ func (log *ConnLogger) GetName() string {
 | 
				
			||||||
	return "conn"
 | 
						return "conn"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ReleaseReopen causes the ConnLogger to reconnect to the server
 | 
				
			||||||
 | 
					func (log *ConnLogger) ReleaseReopen() error {
 | 
				
			||||||
 | 
						return log.out.(*connWriter).releaseReopen()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func init() {
 | 
					func init() {
 | 
				
			||||||
	Register("conn", NewConn)
 | 
						Register("conn", NewConn)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -68,6 +68,20 @@ func (log *ConsoleLogger) Init(config string) error {
 | 
				
			||||||
func (log *ConsoleLogger) Flush() {
 | 
					func (log *ConsoleLogger) Flush() {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ReleaseReopen causes the console logger to reconnect to os.Stdout
 | 
				
			||||||
 | 
					func (log *ConsoleLogger) ReleaseReopen() error {
 | 
				
			||||||
 | 
						if log.Stderr {
 | 
				
			||||||
 | 
							log.NewWriterLogger(&nopWriteCloser{
 | 
				
			||||||
 | 
								w: os.Stderr,
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							log.NewWriterLogger(&nopWriteCloser{
 | 
				
			||||||
 | 
								w: os.Stdout,
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetName returns the default name for this implementation
 | 
					// GetName returns the default name for this implementation
 | 
				
			||||||
func (log *ConsoleLogger) GetName() string {
 | 
					func (log *ConsoleLogger) GetName() string {
 | 
				
			||||||
	return "console"
 | 
						return "console"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,6 +29,7 @@ type EventLogger interface {
 | 
				
			||||||
	GetLevel() Level
 | 
						GetLevel() Level
 | 
				
			||||||
	GetStacktraceLevel() Level
 | 
						GetStacktraceLevel() Level
 | 
				
			||||||
	GetName() string
 | 
						GetName() string
 | 
				
			||||||
 | 
						ReleaseReopen() error
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ChannelledLog represents a cached channel to a LoggerProvider
 | 
					// ChannelledLog represents a cached channel to a LoggerProvider
 | 
				
			||||||
| 
						 | 
					@ -117,6 +118,11 @@ func (l *ChannelledLog) Flush() {
 | 
				
			||||||
	l.flush <- true
 | 
						l.flush <- true
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ReleaseReopen this ChannelledLog
 | 
				
			||||||
 | 
					func (l *ChannelledLog) ReleaseReopen() error {
 | 
				
			||||||
 | 
						return l.loggerProvider.ReleaseReopen()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetLevel gets the level of this ChannelledLog
 | 
					// GetLevel gets the level of this ChannelledLog
 | 
				
			||||||
func (l *ChannelledLog) GetLevel() Level {
 | 
					func (l *ChannelledLog) GetLevel() Level {
 | 
				
			||||||
	return l.loggerProvider.GetLevel()
 | 
						return l.loggerProvider.GetLevel()
 | 
				
			||||||
| 
						 | 
					@ -145,6 +151,7 @@ type MultiChannelledLog struct {
 | 
				
			||||||
	level           Level
 | 
						level           Level
 | 
				
			||||||
	stacktraceLevel Level
 | 
						stacktraceLevel Level
 | 
				
			||||||
	closed          chan bool
 | 
						closed          chan bool
 | 
				
			||||||
 | 
						paused          chan bool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NewMultiChannelledLog a new logger instance with given logger provider and config.
 | 
					// NewMultiChannelledLog a new logger instance with given logger provider and config.
 | 
				
			||||||
| 
						 | 
					@ -159,6 +166,7 @@ func NewMultiChannelledLog(name string, bufferLength int64) *MultiChannelledLog
 | 
				
			||||||
		stacktraceLevel: NONE,
 | 
							stacktraceLevel: NONE,
 | 
				
			||||||
		close:           make(chan bool),
 | 
							close:           make(chan bool),
 | 
				
			||||||
		closed:          make(chan bool),
 | 
							closed:          make(chan bool),
 | 
				
			||||||
 | 
							paused:          make(chan bool),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return m
 | 
						return m
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -229,6 +237,33 @@ func (m *MultiChannelledLog) closeLoggers() {
 | 
				
			||||||
	m.closed <- true
 | 
						m.closed <- true
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Pause pauses this Logger
 | 
				
			||||||
 | 
					func (m *MultiChannelledLog) Pause() {
 | 
				
			||||||
 | 
						m.paused <- true
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Resume resumes this Logger
 | 
				
			||||||
 | 
					func (m *MultiChannelledLog) Resume() {
 | 
				
			||||||
 | 
						m.paused <- false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ReleaseReopen causes this logger to tell its subloggers to release and reopen
 | 
				
			||||||
 | 
					func (m *MultiChannelledLog) ReleaseReopen() error {
 | 
				
			||||||
 | 
						m.mutex.Lock()
 | 
				
			||||||
 | 
						defer m.mutex.Unlock()
 | 
				
			||||||
 | 
						var accumulatedErr error
 | 
				
			||||||
 | 
						for _, logger := range m.loggers {
 | 
				
			||||||
 | 
							if err := logger.ReleaseReopen(); err != nil {
 | 
				
			||||||
 | 
								if accumulatedErr == nil {
 | 
				
			||||||
 | 
									accumulatedErr = fmt.Errorf("Error whilst reopening: %s Error: %v", logger.GetName(), err)
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									accumulatedErr = fmt.Errorf("Error whilst reopening: %s Error: %v & %v", logger.GetName(), err, accumulatedErr)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return accumulatedErr
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Start processing the MultiChannelledLog
 | 
					// Start processing the MultiChannelledLog
 | 
				
			||||||
func (m *MultiChannelledLog) Start() {
 | 
					func (m *MultiChannelledLog) Start() {
 | 
				
			||||||
	m.mutex.Lock()
 | 
						m.mutex.Lock()
 | 
				
			||||||
| 
						 | 
					@ -238,8 +273,35 @@ func (m *MultiChannelledLog) Start() {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	m.started = true
 | 
						m.started = true
 | 
				
			||||||
	m.mutex.Unlock()
 | 
						m.mutex.Unlock()
 | 
				
			||||||
 | 
						paused := false
 | 
				
			||||||
	for {
 | 
						for {
 | 
				
			||||||
 | 
							if paused {
 | 
				
			||||||
			select {
 | 
								select {
 | 
				
			||||||
 | 
								case paused = <-m.paused:
 | 
				
			||||||
 | 
									if !paused {
 | 
				
			||||||
 | 
										m.ResetLevel()
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								case _, ok := <-m.flush:
 | 
				
			||||||
 | 
									if !ok {
 | 
				
			||||||
 | 
										m.closeLoggers()
 | 
				
			||||||
 | 
										return
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									m.mutex.Lock()
 | 
				
			||||||
 | 
									for _, logger := range m.loggers {
 | 
				
			||||||
 | 
										logger.Flush()
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									m.mutex.Unlock()
 | 
				
			||||||
 | 
								case <-m.close:
 | 
				
			||||||
 | 
									m.closeLoggers()
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							select {
 | 
				
			||||||
 | 
							case paused = <-m.paused:
 | 
				
			||||||
 | 
								if paused && m.level < INFO {
 | 
				
			||||||
 | 
									m.level = INFO
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		case event, ok := <-m.queue:
 | 
							case event, ok := <-m.queue:
 | 
				
			||||||
			if !ok {
 | 
								if !ok {
 | 
				
			||||||
				m.closeLoggers()
 | 
									m.closeLoggers()
 | 
				
			||||||
| 
						 | 
					@ -275,7 +337,7 @@ func (m *MultiChannelledLog) LogEvent(event *Event) error {
 | 
				
			||||||
	select {
 | 
						select {
 | 
				
			||||||
	case m.queue <- event:
 | 
						case m.queue <- event:
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	case <-time.After(60 * time.Second):
 | 
						case <-time.After(100 * time.Millisecond):
 | 
				
			||||||
		// We're blocked!
 | 
							// We're blocked!
 | 
				
			||||||
		return ErrTimeout{
 | 
							return ErrTimeout{
 | 
				
			||||||
			Name:     m.name,
 | 
								Name:     m.name,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -249,6 +249,19 @@ func (log *FileLogger) Flush() {
 | 
				
			||||||
	_ = log.mw.fd.Sync()
 | 
						_ = log.mw.fd.Sync()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ReleaseReopen releases and reopens log files
 | 
				
			||||||
 | 
					func (log *FileLogger) ReleaseReopen() error {
 | 
				
			||||||
 | 
						closingErr := log.mw.fd.Close()
 | 
				
			||||||
 | 
						startingErr := log.StartLogger()
 | 
				
			||||||
 | 
						if startingErr != nil {
 | 
				
			||||||
 | 
							if closingErr != nil {
 | 
				
			||||||
 | 
								return fmt.Errorf("Error during closing: %v Error during starting: %v", closingErr, startingErr)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return startingErr
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return closingErr
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetName returns the default name for this implementation
 | 
					// GetName returns the default name for this implementation
 | 
				
			||||||
func (log *FileLogger) GetName() string {
 | 
					func (log *FileLogger) GetName() string {
 | 
				
			||||||
	return "file"
 | 
						return "file"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,6 +5,7 @@
 | 
				
			||||||
package log
 | 
					package log
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"runtime"
 | 
						"runtime"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
| 
						 | 
					@ -192,6 +193,42 @@ func IsFatal() bool {
 | 
				
			||||||
	return GetLevel() <= FATAL
 | 
						return GetLevel() <= FATAL
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Pause pauses all the loggers
 | 
				
			||||||
 | 
					func Pause() {
 | 
				
			||||||
 | 
						NamedLoggers.Range(func(key, value interface{}) bool {
 | 
				
			||||||
 | 
							logger := value.(*Logger)
 | 
				
			||||||
 | 
							logger.Pause()
 | 
				
			||||||
 | 
							logger.Flush()
 | 
				
			||||||
 | 
							return true
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Resume resumes all the loggers
 | 
				
			||||||
 | 
					func Resume() {
 | 
				
			||||||
 | 
						NamedLoggers.Range(func(key, value interface{}) bool {
 | 
				
			||||||
 | 
							logger := value.(*Logger)
 | 
				
			||||||
 | 
							logger.Resume()
 | 
				
			||||||
 | 
							return true
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ReleaseReopen releases and reopens logging files
 | 
				
			||||||
 | 
					func ReleaseReopen() error {
 | 
				
			||||||
 | 
						var accumulatedErr error
 | 
				
			||||||
 | 
						NamedLoggers.Range(func(key, value interface{}) bool {
 | 
				
			||||||
 | 
							logger := value.(*Logger)
 | 
				
			||||||
 | 
							if err := logger.ReleaseReopen(); err != nil {
 | 
				
			||||||
 | 
								if accumulatedErr == nil {
 | 
				
			||||||
 | 
									accumulatedErr = fmt.Errorf("Error reopening %s: %v", key.(string), err)
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									accumulatedErr = fmt.Errorf("Error reopening %s: %v & %v", key.(string), err, accumulatedErr)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return true
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						return accumulatedErr
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Close closes all the loggers
 | 
					// Close closes all the loggers
 | 
				
			||||||
func Close() {
 | 
					func Close() {
 | 
				
			||||||
	l, ok := NamedLoggers.Load(DEFAULT)
 | 
						l, ok := NamedLoggers.Load(DEFAULT)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -97,6 +97,11 @@ func (log *SMTPLogger) sendMail(p []byte) (int, error) {
 | 
				
			||||||
func (log *SMTPLogger) Flush() {
 | 
					func (log *SMTPLogger) Flush() {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ReleaseReopen does nothing
 | 
				
			||||||
 | 
					func (log *SMTPLogger) ReleaseReopen() error {
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetName returns the default name for this implementation
 | 
					// GetName returns the default name for this implementation
 | 
				
			||||||
func (log *SMTPLogger) GetName() string {
 | 
					func (log *SMTPLogger) GetName() string {
 | 
				
			||||||
	return "smtp"
 | 
						return "smtp"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,6 +8,7 @@ import (
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
 | 
						"net/url"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/modules/setting"
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
| 
						 | 
					@ -81,3 +82,110 @@ func FlushQueues(timeout time.Duration, nonBlocking bool) (int, string) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return http.StatusOK, "Flushed"
 | 
						return http.StatusOK, "Flushed"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// PauseLogging pauses logging
 | 
				
			||||||
 | 
					func PauseLogging() (int, string) {
 | 
				
			||||||
 | 
						reqURL := setting.LocalURL + "api/internal/manager/pause-logging"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						req := newInternalRequest(reqURL, "POST")
 | 
				
			||||||
 | 
						resp, err := req.Response()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return http.StatusInternalServerError, fmt.Sprintf("Unable to contact gitea: %v", err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer resp.Body.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if resp.StatusCode != http.StatusOK {
 | 
				
			||||||
 | 
							return resp.StatusCode, decodeJSONError(resp).Err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return http.StatusOK, "Logging Paused"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ResumeLogging resumes logging
 | 
				
			||||||
 | 
					func ResumeLogging() (int, string) {
 | 
				
			||||||
 | 
						reqURL := setting.LocalURL + "api/internal/manager/resume-logging"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						req := newInternalRequest(reqURL, "POST")
 | 
				
			||||||
 | 
						resp, err := req.Response()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return http.StatusInternalServerError, fmt.Sprintf("Unable to contact gitea: %v", err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer resp.Body.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if resp.StatusCode != http.StatusOK {
 | 
				
			||||||
 | 
							return resp.StatusCode, decodeJSONError(resp).Err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return http.StatusOK, "Logging Restarted"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ReleaseReopenLogging releases and reopens logging files
 | 
				
			||||||
 | 
					func ReleaseReopenLogging() (int, string) {
 | 
				
			||||||
 | 
						reqURL := setting.LocalURL + "api/internal/manager/release-and-reopen-logging"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						req := newInternalRequest(reqURL, "POST")
 | 
				
			||||||
 | 
						resp, err := req.Response()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return http.StatusInternalServerError, fmt.Sprintf("Unable to contact gitea: %v", err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer resp.Body.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if resp.StatusCode != http.StatusOK {
 | 
				
			||||||
 | 
							return resp.StatusCode, decodeJSONError(resp).Err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return http.StatusOK, "Logging Restarted"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// LoggerOptions represents the options for the add logger call
 | 
				
			||||||
 | 
					type LoggerOptions struct {
 | 
				
			||||||
 | 
						Group  string
 | 
				
			||||||
 | 
						Name   string
 | 
				
			||||||
 | 
						Mode   string
 | 
				
			||||||
 | 
						Config map[string]interface{}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// AddLogger adds a logger
 | 
				
			||||||
 | 
					func AddLogger(group, name, mode string, config map[string]interface{}) (int, string) {
 | 
				
			||||||
 | 
						reqURL := setting.LocalURL + "api/internal/manager/add-logger"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						req := newInternalRequest(reqURL, "POST")
 | 
				
			||||||
 | 
						req = req.Header("Content-Type", "application/json")
 | 
				
			||||||
 | 
						jsonBytes, _ := json.Marshal(LoggerOptions{
 | 
				
			||||||
 | 
							Group:  group,
 | 
				
			||||||
 | 
							Name:   name,
 | 
				
			||||||
 | 
							Mode:   mode,
 | 
				
			||||||
 | 
							Config: config,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						req.Body(jsonBytes)
 | 
				
			||||||
 | 
						resp, err := req.Response()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return http.StatusInternalServerError, fmt.Sprintf("Unable to contact gitea: %v", err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer resp.Body.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if resp.StatusCode != http.StatusOK {
 | 
				
			||||||
 | 
							return resp.StatusCode, decodeJSONError(resp).Err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return http.StatusOK, "Added"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// RemoveLogger removes a logger
 | 
				
			||||||
 | 
					func RemoveLogger(group, name string) (int, string) {
 | 
				
			||||||
 | 
						reqURL := setting.LocalURL + fmt.Sprintf("api/internal/manager/remove-logger/%s/%s", url.PathEscape(group), url.PathEscape(name))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						req := newInternalRequest(reqURL, "POST")
 | 
				
			||||||
 | 
						resp, err := req.Response()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return http.StatusInternalServerError, fmt.Sprintf("Unable to contact gitea: %v", err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer resp.Body.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if resp.StatusCode != http.StatusOK {
 | 
				
			||||||
 | 
							return resp.StatusCode, decodeJSONError(resp).Err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return http.StatusOK, "Removed"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,6 +12,7 @@ import (
 | 
				
			||||||
	"path"
 | 
						"path"
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
						"sync"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/modules/log"
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,6 +21,69 @@ import (
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var filenameSuffix = ""
 | 
					var filenameSuffix = ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var descriptionLock = sync.RWMutex{}
 | 
				
			||||||
 | 
					var logDescriptions = make(map[string]*LogDescription)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetLogDescriptions returns a race safe set of descriptions
 | 
				
			||||||
 | 
					func GetLogDescriptions() map[string]*LogDescription {
 | 
				
			||||||
 | 
						descriptionLock.RLock()
 | 
				
			||||||
 | 
						defer descriptionLock.RUnlock()
 | 
				
			||||||
 | 
						descs := make(map[string]*LogDescription, len(logDescriptions))
 | 
				
			||||||
 | 
						for k, v := range logDescriptions {
 | 
				
			||||||
 | 
							subLogDescriptions := make([]SubLogDescription, len(v.SubLogDescriptions))
 | 
				
			||||||
 | 
							for i, s := range v.SubLogDescriptions {
 | 
				
			||||||
 | 
								subLogDescriptions[i] = s
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							descs[k] = &LogDescription{
 | 
				
			||||||
 | 
								Name:               v.Name,
 | 
				
			||||||
 | 
								SubLogDescriptions: subLogDescriptions,
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return descs
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// AddLogDescription adds a set of descriptions to the complete description
 | 
				
			||||||
 | 
					func AddLogDescription(key string, description *LogDescription) {
 | 
				
			||||||
 | 
						descriptionLock.Lock()
 | 
				
			||||||
 | 
						defer descriptionLock.Unlock()
 | 
				
			||||||
 | 
						logDescriptions[key] = description
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// AddSubLogDescription adds a sub log description
 | 
				
			||||||
 | 
					func AddSubLogDescription(key string, subLogDescription SubLogDescription) bool {
 | 
				
			||||||
 | 
						descriptionLock.Lock()
 | 
				
			||||||
 | 
						defer descriptionLock.Unlock()
 | 
				
			||||||
 | 
						desc, ok := logDescriptions[key]
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for i, sub := range desc.SubLogDescriptions {
 | 
				
			||||||
 | 
							if sub.Name == subLogDescription.Name {
 | 
				
			||||||
 | 
								desc.SubLogDescriptions[i] = subLogDescription
 | 
				
			||||||
 | 
								return true
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						desc.SubLogDescriptions = append(desc.SubLogDescriptions, subLogDescription)
 | 
				
			||||||
 | 
						return true
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// RemoveSubLogDescription removes a sub log description
 | 
				
			||||||
 | 
					func RemoveSubLogDescription(key string, name string) bool {
 | 
				
			||||||
 | 
						descriptionLock.Lock()
 | 
				
			||||||
 | 
						defer descriptionLock.Unlock()
 | 
				
			||||||
 | 
						desc, ok := logDescriptions[key]
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for i, sub := range desc.SubLogDescriptions {
 | 
				
			||||||
 | 
							if sub.Name == name {
 | 
				
			||||||
 | 
								desc.SubLogDescriptions = append(desc.SubLogDescriptions[:i], desc.SubLogDescriptions[i+1:]...)
 | 
				
			||||||
 | 
								return true
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type defaultLogOptions struct {
 | 
					type defaultLogOptions struct {
 | 
				
			||||||
	levelName      string // LogLevel
 | 
						levelName      string // LogLevel
 | 
				
			||||||
	flags          string
 | 
						flags          string
 | 
				
			||||||
| 
						 | 
					@ -185,7 +249,7 @@ func generateNamedLogger(key string, options defaultLogOptions) *LogDescription
 | 
				
			||||||
		log.Info("%s Log: %s(%s:%s)", strings.Title(key), strings.Title(name), provider, levelName)
 | 
							log.Info("%s Log: %s(%s:%s)", strings.Title(key), strings.Title(name), provider, levelName)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LogDescriptions[key] = &description
 | 
						AddLogDescription(key, &description)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return &description
 | 
						return &description
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -279,7 +343,7 @@ func newLogService() {
 | 
				
			||||||
		log.Info("Gitea Log Mode: %s(%s:%s)", strings.Title(name), strings.Title(provider), levelName)
 | 
							log.Info("Gitea Log Mode: %s(%s:%s)", strings.Title(name), strings.Title(provider), levelName)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LogDescriptions[log.DEFAULT] = &description
 | 
						AddLogDescription(log.DEFAULT, &description)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Finally redirect the default golog to here
 | 
						// Finally redirect the default golog to here
 | 
				
			||||||
	golog.SetFlags(0)
 | 
						golog.SetFlags(0)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -289,7 +289,6 @@ var (
 | 
				
			||||||
	LogLevel           string
 | 
						LogLevel           string
 | 
				
			||||||
	StacktraceLogLevel string
 | 
						StacktraceLogLevel string
 | 
				
			||||||
	LogRootPath        string
 | 
						LogRootPath        string
 | 
				
			||||||
	LogDescriptions    = make(map[string]*LogDescription)
 | 
					 | 
				
			||||||
	RedirectMacaronLog bool
 | 
						RedirectMacaronLog bool
 | 
				
			||||||
	DisableRouterLog   bool
 | 
						DisableRouterLog   bool
 | 
				
			||||||
	RouterLogLevel     log.Level
 | 
						RouterLogLevel     log.Level
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -307,7 +307,7 @@ func Config(ctx *context.Context) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx.Data["EnvVars"] = envVars
 | 
						ctx.Data["EnvVars"] = envVars
 | 
				
			||||||
	ctx.Data["Loggers"] = setting.LogDescriptions
 | 
						ctx.Data["Loggers"] = setting.GetLogDescriptions()
 | 
				
			||||||
	ctx.Data["RedirectMacaronLog"] = setting.RedirectMacaronLog
 | 
						ctx.Data["RedirectMacaronLog"] = setting.RedirectMacaronLog
 | 
				
			||||||
	ctx.Data["EnableAccessLog"] = setting.EnableAccessLog
 | 
						ctx.Data["EnableAccessLog"] = setting.EnableAccessLog
 | 
				
			||||||
	ctx.Data["AccessLogTemplate"] = setting.AccessLogTemplate
 | 
						ctx.Data["AccessLogTemplate"] = setting.AccessLogTemplate
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,6 +42,10 @@ func RegisterRoutes(m *macaron.Macaron) {
 | 
				
			||||||
		m.Post("/manager/shutdown", Shutdown)
 | 
							m.Post("/manager/shutdown", Shutdown)
 | 
				
			||||||
		m.Post("/manager/restart", Restart)
 | 
							m.Post("/manager/restart", Restart)
 | 
				
			||||||
		m.Post("/manager/flush-queues", bind(private.FlushOptions{}), FlushQueues)
 | 
							m.Post("/manager/flush-queues", bind(private.FlushOptions{}), FlushQueues)
 | 
				
			||||||
 | 
							m.Post("/manager/pause-logging", PauseLogging)
 | 
				
			||||||
 | 
							m.Post("/manager/resume-logging", ResumeLogging)
 | 
				
			||||||
 | 
							m.Post("/manager/release-and-reopen-logging", ReleaseReopenLogging)
 | 
				
			||||||
 | 
							m.Post("/manager/add-logger", bind(private.LoggerOptions{}), AddLogger)
 | 
				
			||||||
 | 
							m.Post("/manager/remove-logger/:group/:name", RemoveLogger)
 | 
				
			||||||
	}, CheckInternalToken)
 | 
						}, CheckInternalToken)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,12 +5,15 @@
 | 
				
			||||||
package private
 | 
					package private
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/modules/graceful"
 | 
						"code.gitea.io/gitea/modules/graceful"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/log"
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/private"
 | 
						"code.gitea.io/gitea/modules/private"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/queue"
 | 
						"code.gitea.io/gitea/modules/queue"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"gitea.com/macaron/macaron"
 | 
						"gitea.com/macaron/macaron"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
| 
						 | 
					@ -34,8 +37,120 @@ func FlushQueues(ctx *macaron.Context, opts private.FlushOptions) {
 | 
				
			||||||
	err := queue.GetManager().FlushAll(ctx.Req.Request.Context(), opts.Timeout)
 | 
						err := queue.GetManager().FlushAll(ctx.Req.Request.Context(), opts.Timeout)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		ctx.JSON(http.StatusRequestTimeout, map[string]interface{}{
 | 
							ctx.JSON(http.StatusRequestTimeout, map[string]interface{}{
 | 
				
			||||||
			"err": err,
 | 
								"err": fmt.Sprintf("%v", err),
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ctx.PlainText(http.StatusOK, []byte("success"))
 | 
						ctx.PlainText(http.StatusOK, []byte("success"))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// PauseLogging pauses logging
 | 
				
			||||||
 | 
					func PauseLogging(ctx *macaron.Context) {
 | 
				
			||||||
 | 
						log.Pause()
 | 
				
			||||||
 | 
						ctx.PlainText(http.StatusOK, []byte("success"))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ResumeLogging resumes logging
 | 
				
			||||||
 | 
					func ResumeLogging(ctx *macaron.Context) {
 | 
				
			||||||
 | 
						log.Resume()
 | 
				
			||||||
 | 
						ctx.PlainText(http.StatusOK, []byte("success"))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ReleaseReopenLogging releases and reopens logging files
 | 
				
			||||||
 | 
					func ReleaseReopenLogging(ctx *macaron.Context) {
 | 
				
			||||||
 | 
						if err := log.ReleaseReopen(); err != nil {
 | 
				
			||||||
 | 
							ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
 | 
				
			||||||
 | 
								"err": fmt.Sprintf("Error during release and reopen: %v", err),
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ctx.PlainText(http.StatusOK, []byte("success"))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// RemoveLogger removes a logger
 | 
				
			||||||
 | 
					func RemoveLogger(ctx *macaron.Context) {
 | 
				
			||||||
 | 
						group := ctx.Params("group")
 | 
				
			||||||
 | 
						name := ctx.Params("name")
 | 
				
			||||||
 | 
						ok, err := log.GetLogger(group).DelLogger(name)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
 | 
				
			||||||
 | 
								"err": fmt.Sprintf("Failed to remove logger: %s %s %v", group, name, err),
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if ok {
 | 
				
			||||||
 | 
							setting.RemoveSubLogDescription(group, name)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ctx.PlainText(http.StatusOK, []byte(fmt.Sprintf("Removed %s %s", group, name)))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// AddLogger adds a logger
 | 
				
			||||||
 | 
					func AddLogger(ctx *macaron.Context, opts private.LoggerOptions) {
 | 
				
			||||||
 | 
						if len(opts.Group) == 0 {
 | 
				
			||||||
 | 
							opts.Group = log.DEFAULT
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if _, ok := opts.Config["flags"]; !ok {
 | 
				
			||||||
 | 
							switch opts.Group {
 | 
				
			||||||
 | 
							case "access":
 | 
				
			||||||
 | 
								opts.Config["flags"] = log.FlagsFromString("")
 | 
				
			||||||
 | 
							case "router":
 | 
				
			||||||
 | 
								opts.Config["flags"] = log.FlagsFromString("date,time")
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								opts.Config["flags"] = log.FlagsFromString("stdflags")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if _, ok := opts.Config["colorize"]; !ok && opts.Mode == "console" {
 | 
				
			||||||
 | 
							if _, ok := opts.Config["stderr"]; ok {
 | 
				
			||||||
 | 
								opts.Config["colorize"] = log.CanColorStderr
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								opts.Config["colorize"] = log.CanColorStdout
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if _, ok := opts.Config["level"]; !ok {
 | 
				
			||||||
 | 
							opts.Config["level"] = setting.LogLevel
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if _, ok := opts.Config["stacktraceLevel"]; !ok {
 | 
				
			||||||
 | 
							opts.Config["stacktraceLevel"] = setting.StacktraceLogLevel
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if opts.Mode == "file" {
 | 
				
			||||||
 | 
							if _, ok := opts.Config["maxsize"]; !ok {
 | 
				
			||||||
 | 
								opts.Config["maxsize"] = 1 << 28
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if _, ok := opts.Config["maxdays"]; !ok {
 | 
				
			||||||
 | 
								opts.Config["maxdays"] = 7
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if _, ok := opts.Config["compressionLevel"]; !ok {
 | 
				
			||||||
 | 
								opts.Config["compressionLevel"] = -1
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bufferLen := setting.Cfg.Section("log").Key("BUFFER_LEN").MustInt64(10000)
 | 
				
			||||||
 | 
						byteConfig, err := json.Marshal(opts.Config)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Error("Failed to marshal log configuration: %v %v", opts.Config, err)
 | 
				
			||||||
 | 
							ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
 | 
				
			||||||
 | 
								"err": fmt.Sprintf("Failed to marshal log configuration: %v %v", opts.Config, err),
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						config := string(byteConfig)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := log.NewNamedLogger(opts.Group, bufferLen, opts.Name, opts.Mode, config); err != nil {
 | 
				
			||||||
 | 
							log.Error("Failed to create new named logger: %s %v", config, err)
 | 
				
			||||||
 | 
							ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
 | 
				
			||||||
 | 
								"err": fmt.Sprintf("Failed to create new named logger: %s %v", config, err),
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						setting.AddSubLogDescription(opts.Group, setting.SubLogDescription{
 | 
				
			||||||
 | 
							Name:     opts.Name,
 | 
				
			||||||
 | 
							Provider: opts.Mode,
 | 
				
			||||||
 | 
							Config:   config,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctx.PlainText(http.StatusOK, []byte("success"))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue