adding PM2 processes details as response of ping endpoint if LOG_LEVEL=DEBUG

This commit is contained in:
Julien Neuhart
2019-08-20 15:23:02 +02:00
parent fc27f6b3f0
commit 95c6ecb724
4 changed files with 131 additions and 8 deletions

View File

@@ -8,8 +8,10 @@ import (
"github.com/labstack/echo/v4"
"github.com/thecodingmachine/gotenberg/internal/app/xhttp/pkg/context"
"github.com/thecodingmachine/gotenberg/internal/app/xhttp/pkg/resource"
"github.com/thecodingmachine/gotenberg/internal/pkg/pm2"
"github.com/thecodingmachine/gotenberg/internal/pkg/printer"
"github.com/thecodingmachine/gotenberg/internal/pkg/xerror"
"github.com/thecodingmachine/gotenberg/internal/pkg/xlog"
"github.com/thecodingmachine/gotenberg/internal/pkg/xrand"
"github.com/thecodingmachine/gotenberg/internal/pkg/xtime"
)
@@ -28,11 +30,24 @@ const (
func pingHandler(c echo.Context) error {
const op string = "xhttp.pingHandler"
ctx := context.MustCastFromEchoContext(c)
ctx.XLogger().DebugOp(op, "handling ping request...")
if err := ctx.ProcessesHealthcheck(); err != nil {
logger := ctx.XLogger()
logger.DebugOp(op, "handling ping request...")
resolver := func() error {
if err := ctx.ProcessesHealthcheck(); err != nil {
return err
}
if logger.Level() != xlog.DebugLevel {
return nil
}
list, err := pm2.List()
if err != nil {
return err
}
return ctx.JSON(http.StatusOK, list)
}
if err := resolver(); err != nil {
return xerror.New(op, err)
}
// TODO return processes info
return nil
}

View File

@@ -6,6 +6,7 @@ import (
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
"testing"
"github.com/labstack/echo/v4"
@@ -15,7 +16,26 @@ import (
"github.com/thecodingmachine/gotenberg/test"
)
// TODO test ping handler
func TestPingHandler(t *testing.T) {
// should return 200.
config := conf.DefaultConfig()
srv := New(config)
srv = New(config)
req := httptest.NewRequest(http.MethodGet, pingEndpoint, nil)
test.AssertStatusCode(t, http.StatusOK, srv, req)
// should returns a JSON as
// LOG_LEVEL is "DEBUG".
os.Setenv(conf.LogLevelEnvVar, "DEBUG")
config, err := conf.FromEnv()
assert.Nil(t, err)
srv = New(config)
req = httptest.NewRequest(http.MethodGet, pingEndpoint, nil)
rec := httptest.NewRecorder()
srv.ServeHTTP(rec, req)
assert.Equal(t, "application/json; charset=UTF-8", rec.Header().Get("Content-type"))
assert.Equal(t, http.StatusOK, rec.Code)
os.Unsetenv(conf.LogLevelEnvVar)
}
func TestMergeHandler(t *testing.T) {
config := conf.DefaultConfig()

View File

@@ -1,7 +1,9 @@
package pm2
import (
"encoding/json"
"fmt"
"os/exec"
"github.com/thecodingmachine/gotenberg/internal/pkg/xerror"
"github.com/thecodingmachine/gotenberg/internal/pkg/xexec"
@@ -27,8 +29,68 @@ const (
restartCommand pm2Command = "restart"
stopCommand pm2Command = "stop"
logsCommand pm2Command = "logs"
jlistCommand pm2Command = "jlist"
)
/*
JListItem is a struct
used for unmarshaling
ONE item of the result
of the command "pm2 jlist".
*/
type JListItem struct {
Name string `json:"name"`
PM2Env struct {
Status string `json:"status"`
} `json:"pm2_env"`
Monit struct {
Memory int64 `json:"memory"`
CPU float64 `json:"cpu"`
} `json:"monit"`
}
/*
JList is a struct
used for unmarshaling
the result of the command
"pm2 jlist".
*/
type JList []JListItem
func (list JList) isOnline(p Process) bool {
const onlineStatus string = "online"
for _, item := range list {
if item.Name == p.binary() {
return item.PM2Env.Status == onlineStatus
}
}
return false
}
// List returns the
// processes details.
func List() (*JList, error) {
const op = "pm2.List"
resolver := func() (*JList, error) {
out, err := exec.
Command("pm2", string(jlistCommand)).
Output()
if err != nil {
return nil, err
}
data := &JList{}
if err := json.Unmarshal(out, data); err != nil {
return nil, err
}
return data, nil
}
list, err := resolver()
if err != nil {
return nil, xerror.New(op, err)
}
return list, nil
}
func start(logger xlog.Logger, process Process) error {
const (
op string = "pm2.start"

View File

@@ -32,10 +32,36 @@ func (p unoconvProcess) Start() error {
}
func (p unoconvProcess) IsViable() bool {
// TODO find a way to check if
// the unoconv listener
// is correctly started?
return true
const op string = "pm2.unoconvProcess.IsViable"
p.logger.DebugfOp(
op,
"checking '%s' viability via PM2",
p.Fullname(),
)
list, err := List()
if err != nil {
p.logger.ErrorfOp(
op,
"'%s' seems not viable as retrieving the list of processes via 'pm2 jlist' returned '%v'",
p.Fullname(),
err,
)
return false
}
if list.isOnline(p) {
p.logger.DebugfOp(
op,
"'%s' is viable as its status is 'online'",
p.Fullname(),
)
return true
}
p.logger.DebugfOp(
op,
"'%s' is not viable as its status is not 'online'",
p.Fullname(),
)
return false
}
func (p unoconvProcess) Stop() error {