mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2025-01-04 14:48:42 +00:00
Add log level API (#444)
* Add log level API Signed-off-by: jolheiser <john.olheiser@gmail.com> * Update cli/loglevel/loglevel.go Co-authored-by: Anbraten <anton@ju60.de> * Move API to api routes Signed-off-by: jolheiser <john.olheiser@gmail.com> Co-authored-by: Anbraten <anton@ju60.de>
This commit is contained in:
parent
03bb0e69d8
commit
8e658c135d
8 changed files with 174 additions and 4 deletions
45
cli/loglevel/loglevel.go
Normal file
45
cli/loglevel/loglevel.go
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
package loglevel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
|
||||||
|
"github.com/woodpecker-ci/woodpecker/cli/internal"
|
||||||
|
"github.com/woodpecker-ci/woodpecker/woodpecker-go/woodpecker"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Command exports the log-level command used to change the servers log-level.
|
||||||
|
var Command = cli.Command{
|
||||||
|
Name: "log-level",
|
||||||
|
ArgsUsage: "[level]",
|
||||||
|
Usage: "get the logging level of the server, or set it with [level]",
|
||||||
|
Action: logLevel,
|
||||||
|
}
|
||||||
|
|
||||||
|
func logLevel(c *cli.Context) error {
|
||||||
|
client, err := internal.NewClient(c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var ll *woodpecker.LogLevel
|
||||||
|
arg := c.Args().First()
|
||||||
|
if arg != "" {
|
||||||
|
lvl, err := zerolog.ParseLevel(arg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ll, err = client.SetLogLevel(&woodpecker.LogLevel{
|
||||||
|
Level: lvl.String(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
ll, err = client.LogLevel()
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info().Msgf("Logging level: %s", ll.Level)
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -15,10 +15,11 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
_ "github.com/joho/godotenv/autoload"
|
_ "github.com/joho/godotenv/autoload"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
zlog "github.com/rs/zerolog/log"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
|
|
||||||
"github.com/woodpecker-ci/woodpecker/cli/build"
|
"github.com/woodpecker-ci/woodpecker/cli/build"
|
||||||
|
@ -27,6 +28,7 @@ import (
|
||||||
"github.com/woodpecker-ci/woodpecker/cli/info"
|
"github.com/woodpecker-ci/woodpecker/cli/info"
|
||||||
"github.com/woodpecker-ci/woodpecker/cli/lint"
|
"github.com/woodpecker-ci/woodpecker/cli/lint"
|
||||||
"github.com/woodpecker-ci/woodpecker/cli/log"
|
"github.com/woodpecker-ci/woodpecker/cli/log"
|
||||||
|
"github.com/woodpecker-ci/woodpecker/cli/loglevel"
|
||||||
"github.com/woodpecker-ci/woodpecker/cli/registry"
|
"github.com/woodpecker-ci/woodpecker/cli/registry"
|
||||||
"github.com/woodpecker-ci/woodpecker/cli/repo"
|
"github.com/woodpecker-ci/woodpecker/cli/repo"
|
||||||
"github.com/woodpecker-ci/woodpecker/cli/secret"
|
"github.com/woodpecker-ci/woodpecker/cli/secret"
|
||||||
|
@ -84,10 +86,16 @@ func main() {
|
||||||
repo.Command,
|
repo.Command,
|
||||||
user.Command,
|
user.Command,
|
||||||
lint.Command,
|
lint.Command,
|
||||||
|
loglevel.Command,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
zlog.Logger = zlog.Output(
|
||||||
|
zerolog.ConsoleWriter{
|
||||||
|
Out: os.Stderr,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
if err := app.Run(os.Args); err != nil {
|
if err := app.Run(os.Args); err != nil {
|
||||||
fmt.Fprintln(os.Stderr, err)
|
zlog.Fatal().Err(err).Msg("error running cli")
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,11 @@
|
||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
"github.com/woodpecker-ci/woodpecker/server/store"
|
"github.com/woodpecker-ci/woodpecker/server/store"
|
||||||
"github.com/woodpecker-ci/woodpecker/version"
|
"github.com/woodpecker-ci/woodpecker/version"
|
||||||
|
@ -37,3 +41,31 @@ func Version(c *gin.Context) {
|
||||||
"version": version.String(),
|
"version": version.String(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LogLevel endpoint returns the current logging level
|
||||||
|
func LogLevel(c *gin.Context) {
|
||||||
|
c.JSON(200, gin.H{
|
||||||
|
"log-level": zerolog.GlobalLevel().String(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLogLevel endpoint allows setting the logging level via API
|
||||||
|
func SetLogLevel(c *gin.Context) {
|
||||||
|
logLevel := struct {
|
||||||
|
LogLevel string `json:"log-level"`
|
||||||
|
}{}
|
||||||
|
if err := c.Bind(&logLevel); err != nil {
|
||||||
|
c.AbortWithError(http.StatusBadRequest, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
lvl, err := zerolog.ParseLevel(logLevel.LogLevel)
|
||||||
|
if err != nil {
|
||||||
|
c.AbortWithError(http.StatusBadRequest, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Log().Msgf("log level set to %s", lvl.String())
|
||||||
|
zerolog.SetGlobalLevel(lvl)
|
||||||
|
c.JSON(200, logLevel)
|
||||||
|
}
|
||||||
|
|
|
@ -135,6 +135,13 @@ func apiRoutes(e *gin.Engine) {
|
||||||
debugger.GET("/pprof/trace", debug.TraceHandler())
|
debugger.GET("/pprof/trace", debug.TraceHandler())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logLevel := e.Group("/api/log-level")
|
||||||
|
{
|
||||||
|
logLevel.Use(session.MustAdmin())
|
||||||
|
logLevel.GET("", api.LogLevel)
|
||||||
|
logLevel.POST("", api.SetLogLevel)
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: remove /hook in favor of /api/hook
|
// TODO: remove /hook in favor of /api/hook
|
||||||
e.POST("/hook", api.PostHook)
|
e.POST("/hook", api.PostHook)
|
||||||
e.POST("/api/hook", api.PostHook)
|
e.POST("/api/hook", api.PostHook)
|
||||||
|
|
|
@ -37,6 +37,7 @@ const (
|
||||||
pathBuildQueue = "%s/api/builds"
|
pathBuildQueue = "%s/api/builds"
|
||||||
pathQueue = "%s/api/queue"
|
pathQueue = "%s/api/queue"
|
||||||
pathVersion = "%s/version"
|
pathVersion = "%s/version"
|
||||||
|
pathLogLevel = "%s/api/log-level"
|
||||||
)
|
)
|
||||||
|
|
||||||
type client struct {
|
type client struct {
|
||||||
|
@ -355,6 +356,7 @@ func (c *client) SecretDelete(owner, name, secret string) error {
|
||||||
return c.delete(uri)
|
return c.delete(uri)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// QueueInfo returns queue info
|
||||||
func (c *client) QueueInfo() (*Info, error) {
|
func (c *client) QueueInfo() (*Info, error) {
|
||||||
out := new(Info)
|
out := new(Info)
|
||||||
uri := fmt.Sprintf(pathQueue+"/info", c.addr)
|
uri := fmt.Sprintf(pathQueue+"/info", c.addr)
|
||||||
|
@ -362,6 +364,22 @@ func (c *client) QueueInfo() (*Info, error) {
|
||||||
return out, err
|
return out, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LogLevel returns the current logging level
|
||||||
|
func (c *client) LogLevel() (*LogLevel, error) {
|
||||||
|
out := new(LogLevel)
|
||||||
|
uri := fmt.Sprintf(pathLogLevel, c.addr)
|
||||||
|
err := c.get(uri, out)
|
||||||
|
return out, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLogLevel sets the logging level of the server
|
||||||
|
func (c *client) SetLogLevel(in *LogLevel) (*LogLevel, error) {
|
||||||
|
out := new(LogLevel)
|
||||||
|
uri := fmt.Sprintf(pathLogLevel, c.addr)
|
||||||
|
err := c.post(uri, in, out)
|
||||||
|
return out, err
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// http request helper functions
|
// http request helper functions
|
||||||
//
|
//
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
package woodpecker
|
package woodpecker
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -45,3 +47,48 @@ func Test_QueueInfo(t *testing.T) {
|
||||||
t.Errorf("Unexpected worker count: %v, %v", info, err)
|
t.Errorf("Unexpected worker count: %v, %v", info, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_LogLevel(t *testing.T) {
|
||||||
|
logLevel := "warn"
|
||||||
|
fixtureHandler := func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method == http.MethodPost {
|
||||||
|
var ll LogLevel
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&ll); err != nil {
|
||||||
|
t.Logf("could not decode json: %v\n", err)
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
logLevel = ll.Level
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(w, `{
|
||||||
|
"log-level": "%s"
|
||||||
|
}`, logLevel)
|
||||||
|
}
|
||||||
|
|
||||||
|
ts := httptest.NewServer(http.HandlerFunc(fixtureHandler))
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
|
client := NewClient(ts.URL, http.DefaultClient)
|
||||||
|
|
||||||
|
curLvl, err := client.LogLevel()
|
||||||
|
if err != nil {
|
||||||
|
t.Logf("could not get current log level: %v", err)
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.EqualFold(curLvl.Level, logLevel) {
|
||||||
|
t.Logf("log level is not correct\n\tExpected: %s\n\t Got: %s\n", logLevel, curLvl.Level)
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
newLvl, err := client.SetLogLevel(&LogLevel{Level: "trace"})
|
||||||
|
if err != nil {
|
||||||
|
t.Logf("could not set log level: %v", err)
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.EqualFold(newLvl.Level, logLevel) {
|
||||||
|
t.Logf("log level is not correct\n\tExpected: %s\n\t Got: %s\n", logLevel, newLvl.Level)
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package woodpecker
|
package woodpecker
|
||||||
|
|
||||||
import "net/http"
|
import (
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
// Client is used to communicate with a Drone server.
|
// Client is used to communicate with a Drone server.
|
||||||
type Client interface {
|
type Client interface {
|
||||||
|
@ -125,4 +127,10 @@ type Client interface {
|
||||||
|
|
||||||
// QueueInfo returns the queue state.
|
// QueueInfo returns the queue state.
|
||||||
QueueInfo() (*Info, error)
|
QueueInfo() (*Info, error)
|
||||||
|
|
||||||
|
// LogLevel returns the current logging level
|
||||||
|
LogLevel() (*LogLevel, error)
|
||||||
|
|
||||||
|
// SetLogLevel sets the server's logging level
|
||||||
|
SetLogLevel(logLevel *LogLevel) (*LogLevel, error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,4 +152,9 @@ type (
|
||||||
} `json:"stats"`
|
} `json:"stats"`
|
||||||
Paused bool `json:"paused,omitempty"`
|
Paused bool `json:"paused,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LogLevel is for checking/setting logging level
|
||||||
|
LogLevel struct {
|
||||||
|
Level string `json:"log-level"`
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue