mirror of
https://github.com/gotenberg/gotenberg.git
synced 2026-08-14 03:12:14 +01:00
feat: add metrics system, move webhook feature to dedicated module (#372)
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/chromedp/cdproto/fetch"
|
||||
@@ -236,19 +237,35 @@ func (mod Chromium) Validate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Metrics returns the metrics.
|
||||
func (mod Chromium) Metrics() ([]gotenberg.Metric, error) {
|
||||
return []gotenberg.Metric{
|
||||
{
|
||||
Name: "chromium_active_instances_count",
|
||||
Description: "Current number of active Chromium instances.",
|
||||
Read: func() float64 {
|
||||
activeInstancesCountMu.RLock()
|
||||
defer activeInstancesCountMu.RUnlock()
|
||||
|
||||
return activeInstancesCount
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Chromium returns an API for interacting with Chromium for converting HTML
|
||||
// documents to PDF.
|
||||
func (mod Chromium) Chromium() (API, error) {
|
||||
return mod, nil
|
||||
}
|
||||
|
||||
// Routes returns the API routes.
|
||||
func (mod Chromium) Routes() ([]api.MultipartFormDataRoute, error) {
|
||||
// Routes returns the HTTP routes.
|
||||
func (mod Chromium) Routes() ([]api.Route, error) {
|
||||
if mod.disableRoutes {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return []api.MultipartFormDataRoute{
|
||||
return []api.Route{
|
||||
convertURLRoute(mod, mod.engine),
|
||||
convertHTMLRoute(mod, mod.engine),
|
||||
convertMarkdownRoute(mod, mod.engine),
|
||||
@@ -475,9 +492,17 @@ func (mod Chromium) PDF(ctx context.Context, logger *zap.Logger, URL, outputPath
|
||||
}
|
||||
}
|
||||
|
||||
activeInstancesCountMu.Lock()
|
||||
activeInstancesCount += 1
|
||||
activeInstancesCountMu.Unlock()
|
||||
|
||||
var buffer []byte
|
||||
err := chromedp.Run(taskCtx, printToPDF(URL, options, &buffer))
|
||||
|
||||
activeInstancesCountMu.Lock()
|
||||
activeInstancesCount -= 1
|
||||
activeInstancesCountMu.Unlock()
|
||||
|
||||
// Always remove the user profile directory created by Chromium.
|
||||
go func() {
|
||||
logger.Debug(fmt.Sprintf("remove user profile directory '%s'", userProfileDirPath))
|
||||
@@ -514,12 +539,18 @@ func (mod Chromium) PDF(ctx context.Context, logger *zap.Logger, URL, outputPath
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
activeInstancesCount float64
|
||||
activeInstancesCountMu sync.RWMutex
|
||||
)
|
||||
|
||||
// Interface guards.
|
||||
var (
|
||||
_ gotenberg.Module = (*Chromium)(nil)
|
||||
_ gotenberg.Provisioner = (*Chromium)(nil)
|
||||
_ gotenberg.Validator = (*Chromium)(nil)
|
||||
_ api.MultipartFormDataRouter = (*Chromium)(nil)
|
||||
_ API = (*Chromium)(nil)
|
||||
_ Provider = (*Chromium)(nil)
|
||||
_ gotenberg.Module = (*Chromium)(nil)
|
||||
_ gotenberg.Provisioner = (*Chromium)(nil)
|
||||
_ gotenberg.Validator = (*Chromium)(nil)
|
||||
_ gotenberg.MetricsProvider = (*Chromium)(nil)
|
||||
_ api.Router = (*Chromium)(nil)
|
||||
_ API = (*Chromium)(nil)
|
||||
_ Provider = (*Chromium)(nil)
|
||||
)
|
||||
|
||||
@@ -173,6 +173,22 @@ func TestChromium_Validate(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestChromium_Metrics(t *testing.T) {
|
||||
metrics, err := new(Chromium).Metrics()
|
||||
if err != nil {
|
||||
t.Errorf("expected no error but got: %v", err)
|
||||
}
|
||||
|
||||
if len(metrics) != 1 {
|
||||
t.Errorf("expected %d metrics, but got %d", 1, len(metrics))
|
||||
}
|
||||
|
||||
actual := metrics[0].Read()
|
||||
if actual != 0 {
|
||||
t.Errorf("expected %d Chromium instances, but got %f", 0, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestChromium_Chromium(t *testing.T) {
|
||||
mod := new(Chromium)
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
|
||||
"github.com/gotenberg/gotenberg/v7/pkg/gotenberg"
|
||||
"github.com/gotenberg/gotenberg/v7/pkg/modules/api"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/microcosm-cc/bluemonday"
|
||||
"github.com/russross/blackfriday/v2"
|
||||
"go.uber.org/multierr"
|
||||
@@ -89,12 +90,14 @@ func FormDataChromiumPDFOptions(ctx *api.Context) (*api.FormData, Options) {
|
||||
return form, options
|
||||
}
|
||||
|
||||
// convertURLRoute returns an api.MultipartFormDataRoute route which can
|
||||
// convert a URL to PDF.
|
||||
func convertURLRoute(chromium API, engine gotenberg.PDFEngine) api.MultipartFormDataRoute {
|
||||
return api.MultipartFormDataRoute{
|
||||
Path: "/chromium/convert/url",
|
||||
Handler: func(ctx *api.Context) error {
|
||||
// convertURLRoute returns an api.Route which can convert a URL to PDF.
|
||||
func convertURLRoute(chromium API, engine gotenberg.PDFEngine) api.Route {
|
||||
return api.Route{
|
||||
Method: http.MethodPost,
|
||||
Path: "/forms/chromium/convert/url",
|
||||
IsMultipart: true,
|
||||
Handler: func(c echo.Context) error {
|
||||
ctx := c.Get("context").(*api.Context)
|
||||
form, options := FormDataChromiumPDFOptions(ctx)
|
||||
|
||||
var (
|
||||
@@ -121,12 +124,14 @@ func convertURLRoute(chromium API, engine gotenberg.PDFEngine) api.MultipartForm
|
||||
}
|
||||
}
|
||||
|
||||
// convertHTMLRoute returns an api.MultipartFormDataRoute route which can
|
||||
// convert an HTML file to PDF.
|
||||
func convertHTMLRoute(chromium API, engine gotenberg.PDFEngine) api.MultipartFormDataRoute {
|
||||
return api.MultipartFormDataRoute{
|
||||
Path: "/chromium/convert/html",
|
||||
Handler: func(ctx *api.Context) error {
|
||||
// convertHTMLRoute returns an api.Route which can convert an HTML file to PDF.
|
||||
func convertHTMLRoute(chromium API, engine gotenberg.PDFEngine) api.Route {
|
||||
return api.Route{
|
||||
Method: http.MethodPost,
|
||||
Path: "/forms/chromium/convert/html",
|
||||
IsMultipart: true,
|
||||
Handler: func(c echo.Context) error {
|
||||
ctx := c.Get("context").(*api.Context)
|
||||
form, options := FormDataChromiumPDFOptions(ctx)
|
||||
|
||||
var (
|
||||
@@ -155,12 +160,15 @@ func convertHTMLRoute(chromium API, engine gotenberg.PDFEngine) api.MultipartFor
|
||||
}
|
||||
}
|
||||
|
||||
// convertMarkdownRoute returns an api.MultipartFormDataRoute route which can
|
||||
// convert markdown files to PDF.
|
||||
func convertMarkdownRoute(chromium API, engine gotenberg.PDFEngine) api.MultipartFormDataRoute {
|
||||
return api.MultipartFormDataRoute{
|
||||
Path: "/chromium/convert/markdown",
|
||||
Handler: func(ctx *api.Context) error {
|
||||
// convertMarkdownRoute returns an api.Route which can convert markdown files
|
||||
// to PDF.
|
||||
func convertMarkdownRoute(chromium API, engine gotenberg.PDFEngine) api.Route {
|
||||
return api.Route{
|
||||
Method: http.MethodPost,
|
||||
Path: "/forms/chromium/convert/markdown",
|
||||
IsMultipart: true,
|
||||
Handler: func(c echo.Context) error {
|
||||
ctx := c.Get("context").(*api.Context)
|
||||
form, options := FormDataChromiumPDFOptions(ctx)
|
||||
|
||||
var (
|
||||
|
||||
@@ -3,13 +3,14 @@ package chromium
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/gotenberg/gotenberg/v7/pkg/gotenberg"
|
||||
"net/http"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/gotenberg/gotenberg/v7/pkg/gotenberg"
|
||||
"github.com/gotenberg/gotenberg/v7/pkg/modules/api"
|
||||
"github.com/labstack/echo/v4"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
@@ -137,7 +138,10 @@ func TestConvertURLHandler(t *testing.T) {
|
||||
expectOutputPathsCount: 1,
|
||||
},
|
||||
} {
|
||||
err := convertURLRoute(tc.api, nil).Handler(tc.ctx.Context)
|
||||
c := echo.New().NewContext(nil, nil)
|
||||
c.Set("context", tc.ctx.Context)
|
||||
|
||||
err := convertURLRoute(tc.api, nil).Handler(c)
|
||||
|
||||
if tc.expectErr && err == nil {
|
||||
t.Errorf("test %d: expected error but got: %v", i, err)
|
||||
@@ -238,7 +242,10 @@ func TestConvertHTMLHandler(t *testing.T) {
|
||||
expectOutputPathsCount: 1,
|
||||
},
|
||||
} {
|
||||
err := convertHTMLRoute(tc.api, nil).Handler(tc.ctx.Context)
|
||||
c := echo.New().NewContext(nil, nil)
|
||||
c.Set("context", tc.ctx.Context)
|
||||
|
||||
err := convertHTMLRoute(tc.api, nil).Handler(c)
|
||||
|
||||
if tc.expectErr && err == nil {
|
||||
t.Errorf("test %d: expected error but got: %v", i, err)
|
||||
@@ -472,7 +479,10 @@ func TestConvertMarkdownHandler(t *testing.T) {
|
||||
}()
|
||||
}
|
||||
|
||||
err := convertMarkdownRoute(tc.api, nil).Handler(tc.ctx.Context)
|
||||
c := echo.New().NewContext(nil, nil)
|
||||
c.Set("context", tc.ctx.Context)
|
||||
|
||||
err := convertMarkdownRoute(tc.api, nil).Handler(c)
|
||||
|
||||
if tc.expectErr && err == nil {
|
||||
t.Errorf("test %d: expected error but got: %v", i, err)
|
||||
|
||||
Reference in New Issue
Block a user