From 2d3349eee632e7357ed1eb6905444194a28a4ec0 Mon Sep 17 00:00:00 2001 From: Wolfy-J Date: Mon, 26 Oct 2020 21:02:56 +0300 Subject: - working on new cmd and logger setup --- composer.json | 7 +- go.mod | 1 + plugins/app/app.go | 164 +++++++++++++++++++++++++ plugins/app/config.go | 37 ++++++ plugins/app/tests/.rr.yaml | 9 ++ plugins/app/tests/factory_test.go | 78 ++++++++++++ plugins/app/tests/hello.php | 1 + plugins/app/tests/plugin_1.go | 55 +++++++++ plugins/app/tests/plugin_2.go | 88 +++++++++++++ plugins/factory/app.go | 160 ------------------------ plugins/factory/config.go | 37 ------ plugins/factory/tests/.rr.yaml | 9 -- plugins/factory/tests/factory_test.go | 78 ------------ plugins/factory/tests/hello.php | 1 - plugins/factory/tests/plugin_1.go | 55 --------- plugins/factory/tests/plugin_2.go | 88 ------------- plugins/logger/config.go | 9 ++ plugins/logger/zap_logger.go | 111 +++++++++++++++++ src/Diactoros/ServerRequestFactory.php | 26 ---- src/Diactoros/StreamFactory.php | 57 --------- src/Diactoros/UploadedFileFactory.php | 36 ------ src/Exception/RoadRunnerException.php | 2 +- src/Exceptions/RoadRunnerException.php | 18 --- src/Http/HttpClient.php | 75 ++++++++++++ src/Http/PSR7Client.php | 217 +++++++++++++++++++++++++++++++++ src/HttpClient.php | 75 ------------ src/Logger/.empty | 0 src/Metrics.php | 80 ------------ src/Metrics/Metrics.php | 80 ++++++++++++ src/Metrics/MetricsInterface.php | 64 ++++++++++ src/MetricsInterface.php | 64 ---------- src/PSR7Client.php | 217 --------------------------------- src/WorkerInterface.php | 0 33 files changed, 993 insertions(+), 1006 deletions(-) create mode 100644 plugins/app/app.go create mode 100644 plugins/app/config.go create mode 100644 plugins/app/tests/.rr.yaml create mode 100644 plugins/app/tests/factory_test.go create mode 100644 plugins/app/tests/hello.php create mode 100644 plugins/app/tests/plugin_1.go create mode 100644 plugins/app/tests/plugin_2.go delete mode 100755 plugins/factory/app.go delete mode 100755 plugins/factory/config.go delete mode 100755 plugins/factory/tests/.rr.yaml delete mode 100755 plugins/factory/tests/factory_test.go delete mode 100755 plugins/factory/tests/hello.php delete mode 100755 plugins/factory/tests/plugin_1.go delete mode 100755 plugins/factory/tests/plugin_2.go create mode 100644 plugins/logger/config.go create mode 100644 plugins/logger/zap_logger.go delete mode 100755 src/Diactoros/ServerRequestFactory.php delete mode 100755 src/Diactoros/StreamFactory.php delete mode 100755 src/Diactoros/UploadedFileFactory.php delete mode 100755 src/Exceptions/RoadRunnerException.php create mode 100644 src/Http/HttpClient.php create mode 100644 src/Http/PSR7Client.php delete mode 100755 src/HttpClient.php create mode 100644 src/Logger/.empty delete mode 100755 src/Metrics.php create mode 100644 src/Metrics/Metrics.php create mode 100644 src/Metrics/MetricsInterface.php delete mode 100755 src/MetricsInterface.php delete mode 100755 src/PSR7Client.php create mode 100644 src/WorkerInterface.php diff --git a/composer.json b/composer.json index 283eaab1..aef75b08 100755 --- a/composer.json +++ b/composer.json @@ -18,15 +18,14 @@ "ext-json": "*", "ext-curl": "*", "spiral/goridge": "^2.4.2", - "psr/http-factory": "^1.0", - "psr/http-message": "^1.0", - "symfony/console": "^2.5.0 || ^3.0.0 || ^4.0.0 || ^5.0.0", - "laminas/laminas-diactoros": "^1.3 || ^2.0" + "symfony/console": "^2.5.0 || ^3.0.0 || ^4.0.0 || ^5.0.0" }, "config": { "vendor-dir": "vendor_php" }, "require-dev": { + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0", "phpstan/phpstan": "~0.12" }, "scripts": { diff --git a/go.mod b/go.mod index 5adc9293..4fff8f62 100755 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( github.com/stretchr/testify v1.6.1 github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a go.uber.org/multierr v1.6.0 + go.uber.org/zap v1.16.0 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 // indirect gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect diff --git a/plugins/app/app.go b/plugins/app/app.go new file mode 100644 index 00000000..950d7791 --- /dev/null +++ b/plugins/app/app.go @@ -0,0 +1,164 @@ +package app + +import ( + "context" + "fmt" + "log" + "os" + "os/exec" + "strings" + + "github.com/fatih/color" + "github.com/spiral/endure/errors" + "github.com/spiral/roadrunner/v2" + "github.com/spiral/roadrunner/v2/plugins/config" + "github.com/spiral/roadrunner/v2/util" +) + +const ServiceName = "app" + +type Env map[string]string + +// WorkerFactory creates workers for the application. +type WorkerFactory interface { + CmdFactory(env Env) (func() *exec.Cmd, error) + NewWorker(ctx context.Context, env Env) (roadrunner.WorkerBase, error) + NewWorkerPool(ctx context.Context, opt roadrunner.Config, env Env) (roadrunner.Pool, error) +} + +// App manages worker +type App struct { + cfg Config + factory roadrunner.Factory +} + +// Init application provider. +func (app *App) Init(cfg config.Provider) error { + err := cfg.UnmarshalKey(ServiceName, &app.cfg) + if err != nil { + return err + } + app.cfg.InitDefaults() + + return nil +} + +// Name contains service name. +func (app *App) Name() string { + return ServiceName +} + +func (app *App) Serve() chan error { + errCh := make(chan error, 1) + var err error + + app.factory, err = app.initFactory() + if err != nil { + errCh <- errors.E(errors.Op("init factory"), err) + } + + return errCh +} + +func (app *App) Stop() error { + if app.factory == nil { + return nil + } + + return app.factory.Close(context.Background()) +} + +// CmdFactory provides worker command factory assocated with given context. +func (app *App) CmdFactory(env Env) (func() *exec.Cmd, error) { + var cmdArgs []string + + // create command according to the config + cmdArgs = append(cmdArgs, strings.Split(app.cfg.Command, " ")...) + + return func() *exec.Cmd { + cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...) + util.IsolateProcess(cmd) + + // if user is not empty, and OS is linux or macos + // execute php worker from that particular user + if app.cfg.User != "" { + err := util.ExecuteFromUser(cmd, app.cfg.User) + if err != nil { + return nil + } + } + + cmd.Env = app.setEnv(env) + + return cmd + }, nil +} + +// NewWorker issues new standalone worker. +func (app *App) NewWorker(ctx context.Context, env Env) (roadrunner.WorkerBase, error) { + spawnCmd, err := app.CmdFactory(env) + if err != nil { + return nil, err + } + + return app.factory.SpawnWorkerWithContext(ctx, spawnCmd()) +} + +// NewWorkerPool issues new worker pool. +func (app *App) NewWorkerPool(ctx context.Context, opt roadrunner.Config, env Env) (roadrunner.Pool, error) { + spawnCmd, err := app.CmdFactory(env) + if err != nil { + return nil, err + } + + p, err := roadrunner.NewPool(ctx, spawnCmd, app.factory, opt) + if err != nil { + return nil, err + } + + p.AddListener(func(event interface{}) { + if we, ok := event.(roadrunner.WorkerEvent); ok { + if we.Event == roadrunner.EventWorkerLog { + log.Print(color.YellowString(string(we.Payload.([]byte)))) + } + } + }) + + return p, nil +} + +// creates relay and worker factory. +func (app *App) initFactory() (roadrunner.Factory, error) { + if app.cfg.Relay == "" || app.cfg.Relay == "pipes" { + return roadrunner.NewPipeFactory(), nil + } + + dsn := strings.Split(app.cfg.Relay, "://") + if len(dsn) != 2 { + return nil, errors.E(errors.Str("invalid DSN (tcp://:6001, unix://file.sock)")) + } + + lsn, err := util.CreateListener(app.cfg.Relay) + if err != nil { + return nil, err + } + + switch dsn[0] { + // sockets group + case "unix": + return roadrunner.NewSocketServer(lsn, app.cfg.RelayTimeout), nil + case "tcp": + return roadrunner.NewSocketServer(lsn, app.cfg.RelayTimeout), nil + default: + return nil, errors.E(errors.Str("invalid DSN (tcp://:6001, unix://file.sock)")) + } +} + +func (app *App) setEnv(e Env) []string { + env := append(os.Environ(), fmt.Sprintf("RR_RELAY=%s", app.cfg.Relay)) + for k, v := range e { + env = append(env, fmt.Sprintf("%s=%s", strings.ToUpper(k), v)) + } + + return env +} diff --git a/plugins/app/config.go b/plugins/app/config.go new file mode 100644 index 00000000..eaa54e2d --- /dev/null +++ b/plugins/app/config.go @@ -0,0 +1,37 @@ +package app + +import "time" + +// Config config combines factory, pool and cmd configurations. +type Config struct { + // Command to run as application. + Command string + + // User to run application under. + User string + + // Group to run application under. + Group string + + // Env represents application environment. + Env Env + + // Listen defines connection method and factory to be used to connect to workers: + // "pipes", "tcp://:6001", "unix://rr.sock" + // This config section must not change on re-configuration. + Relay string + + // RelayTimeout defines for how long socket factory will be waiting for worker connection. This config section + // must not change on re-configuration. Defaults to 60s. + RelayTimeout time.Duration +} + +func (cfg *Config) InitDefaults() { + if cfg.Relay == "" { + cfg.Relay = "pipes" + } + + if cfg.RelayTimeout == 0 { + cfg.RelayTimeout = time.Second * 60 + } +} diff --git a/plugins/app/tests/.rr.yaml b/plugins/app/tests/.rr.yaml new file mode 100644 index 00000000..171f51dc --- /dev/null +++ b/plugins/app/tests/.rr.yaml @@ -0,0 +1,9 @@ +app: + command: "php hello.php" + user: "" + group: "" + env: + "RR_CONFIG": "/some/place/on/the/C134" + "RR_CONFIG2": "C138" + relay: "pipes" + relayTimeout: "20s" \ No newline at end of file diff --git a/plugins/app/tests/factory_test.go b/plugins/app/tests/factory_test.go new file mode 100644 index 00000000..7c885797 --- /dev/null +++ b/plugins/app/tests/factory_test.go @@ -0,0 +1,78 @@ +package tests + +import ( + "os" + "os/signal" + "testing" + "time" + + "github.com/spiral/endure" + "github.com/spiral/roadrunner/v2/plugins/app" + "github.com/spiral/roadrunner/v2/plugins/config" + "github.com/stretchr/testify/assert" +) + +func TestFactory(t *testing.T) { + container, err := endure.NewContainer(endure.DebugLevel, endure.RetryOnFail(true)) + if err != nil { + t.Fatal(err) + } + // config plugin + vp := &config.ViperProvider{} + vp.Path = ".rr.yaml" + vp.Prefix = "rr" + err = container.Register(vp) + if err != nil { + t.Fatal(err) + } + + err = container.Register(&app.App{}) + if err != nil { + t.Fatal(err) + } + + err = container.Register(&Foo{}) + if err != nil { + t.Fatal(err) + } + + err = container.Register(&Foo2{}) + if err != nil { + t.Fatal(err) + } + + err = container.Init() + if err != nil { + t.Fatal(err) + } + + errCh, err := container.Serve() + if err != nil { + t.Fatal(err) + } + + // stop by CTRL+C + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt) + + tt := time.NewTicker(time.Second * 2) + + for { + select { + case e := <-errCh: + assert.NoError(t, e.Error) + assert.NoError(t, container.Stop()) + return + case <-c: + er := container.Stop() + if er != nil { + panic(er) + } + return + case <-tt.C: + tt.Stop() + assert.NoError(t, container.Stop()) + return + } + } +} diff --git a/plugins/app/tests/hello.php b/plugins/app/tests/hello.php new file mode 100644 index 00000000..bf9e82cc --- /dev/null +++ b/plugins/app/tests/hello.php @@ -0,0 +1 @@ +createStreamFromResource($resource); - } - - /** - * @inheritdoc - */ - public function createStreamFromFile(string $file, string $mode = 'rb'): StreamInterface - { - $resource = fopen($file, $mode); - - if (! \is_resource($resource)) { - throw new RuntimeException('Cannot create stream'); - } - - return $this->createStreamFromResource($resource); - } - - /** - * @inheritdoc - */ - public function createStreamFromResource($resource): StreamInterface - { - return new Stream($resource); - } -} diff --git a/src/Diactoros/UploadedFileFactory.php b/src/Diactoros/UploadedFileFactory.php deleted file mode 100755 index 45773287..00000000 --- a/src/Diactoros/UploadedFileFactory.php +++ /dev/null @@ -1,36 +0,0 @@ -getSize(); - } - - /** @var resource $stream */ - return new UploadedFile($stream, $size, $error, $clientFilename, $clientMediaType); - } -} diff --git a/src/Exception/RoadRunnerException.php b/src/Exception/RoadRunnerException.php index f83c3dd4..cd657502 100755 --- a/src/Exception/RoadRunnerException.php +++ b/src/Exception/RoadRunnerException.php @@ -9,6 +9,6 @@ declare(strict_types=1); namespace Spiral\RoadRunner\Exception; -class RoadRunnerException extends \Spiral\RoadRunner\Exceptions\RoadRunnerException +class RoadRunnerException extends \RuntimeException { } diff --git a/src/Exceptions/RoadRunnerException.php b/src/Exceptions/RoadRunnerException.php deleted file mode 100755 index 43967893..00000000 --- a/src/Exceptions/RoadRunnerException.php +++ /dev/null @@ -1,18 +0,0 @@ -worker = $worker; + } + + /** + * @return Worker + */ + public function getWorker(): Worker + { + return $this->worker; + } + + /** + * @return mixed[]|null Request information as ['ctx'=>[], 'body'=>string] + * or null if termination request or invalid context. + */ + public function acceptRequest(): ?array + { + $body = $this->getWorker()->receive($ctx); + if (empty($body) && empty($ctx)) { + // termination request + return null; + } + + $ctx = json_decode($ctx, true); + if ($ctx === null) { + // invalid context + return null; + } + + return ['ctx' => $ctx, 'body' => $body]; + } + + /** + * Send response to the application server. + * + * @param int $status Http status code + * @param string $body Body of response + * @param string[][] $headers An associative array of the message's headers. Each + * key MUST be a header name, and each value MUST be an array of strings + * for that header. + */ + public function respond(int $status, string $body, array $headers = []): void + { + if (empty($headers)) { + // this is required to represent empty header set as map and not as array + $headers = new \stdClass(); + } + + $this->getWorker()->send( + $body, + (string) json_encode(['status' => $status, 'headers' => $headers]) + ); + } +} diff --git a/src/Http/PSR7Client.php b/src/Http/PSR7Client.php new file mode 100644 index 00000000..94a9457b --- /dev/null +++ b/src/Http/PSR7Client.php @@ -0,0 +1,217 @@ +httpClient = new HttpClient($worker); + $this->requestFactory = $requestFactory ?? new Diactoros\ServerRequestFactory(); + $this->streamFactory = $streamFactory ?? new Diactoros\StreamFactory(); + $this->uploadsFactory = $uploadsFactory ?? new Diactoros\UploadedFileFactory(); + $this->originalServer = $_SERVER; + } + + /** + * @return Worker + */ + public function getWorker(): Worker + { + return $this->httpClient->getWorker(); + } + + /** + * @return ServerRequestInterface|null + */ + public function acceptRequest(): ?ServerRequestInterface + { + $rawRequest = $this->httpClient->acceptRequest(); + if ($rawRequest === null) { + return null; + } + + $_SERVER = $this->configureServer($rawRequest['ctx']); + + $request = $this->requestFactory->createServerRequest( + $rawRequest['ctx']['method'], + $rawRequest['ctx']['uri'], + $_SERVER + ); + + parse_str($rawRequest['ctx']['rawQuery'], $query); + + $request = $request + ->withProtocolVersion(static::fetchProtocolVersion($rawRequest['ctx']['protocol'])) + ->withCookieParams($rawRequest['ctx']['cookies']) + ->withQueryParams($query) + ->withUploadedFiles($this->wrapUploads($rawRequest['ctx']['uploads'])); + + foreach ($rawRequest['ctx']['attributes'] as $name => $value) { + $request = $request->withAttribute($name, $value); + } + + foreach ($rawRequest['ctx']['headers'] as $name => $value) { + $request = $request->withHeader($name, $value); + } + + if ($rawRequest['ctx']['parsed']) { + return $request->withParsedBody(json_decode($rawRequest['body'], true)); + } + + if ($rawRequest['body'] !== null) { + return $request->withBody($this->streamFactory->createStream($rawRequest['body'])); + } + + return $request; + } + + /** + * Send response to the application server. + * + * @param ResponseInterface $response + */ + public function respond(ResponseInterface $response): void + { + $this->httpClient->respond( + $response->getStatusCode(), + $response->getBody()->__toString(), + $response->getHeaders() + ); + } + + /** + * Returns altered copy of _SERVER variable. Sets ip-address, + * request-time and other values. + * + * @param mixed[] $ctx + * @return mixed[] + */ + protected function configureServer(array $ctx): array + { + $server = $this->originalServer; + + $server['REQUEST_URI'] = $ctx['uri']; + $server['REQUEST_TIME'] = time(); + $server['REQUEST_TIME_FLOAT'] = microtime(true); + $server['REMOTE_ADDR'] = $ctx['attributes']['ipAddress'] ?? $ctx['remoteAddr'] ?? '127.0.0.1'; + $server['REQUEST_METHOD'] = $ctx['method']; + + $server['HTTP_USER_AGENT'] = ''; + foreach ($ctx['headers'] as $key => $value) { + $key = strtoupper(str_replace('-', '_', $key)); + if (\in_array($key, ['CONTENT_TYPE', 'CONTENT_LENGTH'])) { + $server[$key] = implode(', ', $value); + } else { + $server['HTTP_' . $key] = implode(', ', $value); + } + } + + return $server; + } + + /** + * Wraps all uploaded files with UploadedFile. + * + * @param array[] $files + * + * @return UploadedFileInterface[]|mixed[] + */ + private function wrapUploads($files): array + { + if (empty($files)) { + return []; + } + + $result = []; + foreach ($files as $index => $f) { + if (!isset($f['name'])) { + $result[$index] = $this->wrapUploads($f); + continue; + } + + if (UPLOAD_ERR_OK === $f['error']) { + $stream = $this->streamFactory->createStreamFromFile($f['tmpName']); + } else { + $stream = $this->streamFactory->createStream(); + } + + $result[$index] = $this->uploadsFactory->createUploadedFile( + $stream, + $f['size'], + $f['error'], + $f['name'], + $f['mime'] + ); + } + + return $result; + } + + /** + * Normalize HTTP protocol version to valid values + * + * @param string $version + * @return string + */ + private static function fetchProtocolVersion(string $version): string + { + $v = substr($version, 5); + + if ($v === '2.0') { + return '2'; + } + + // Fallback for values outside of valid protocol versions + if (!in_array($v, static::$allowedVersions, true)) { + return '1.1'; + } + + return $v; + } +} diff --git a/src/HttpClient.php b/src/HttpClient.php deleted file mode 100755 index 4ca152c8..00000000 --- a/src/HttpClient.php +++ /dev/null @@ -1,75 +0,0 @@ -worker = $worker; - } - - /** - * @return Worker - */ - public function getWorker(): Worker - { - return $this->worker; - } - - /** - * @return mixed[]|null Request information as ['ctx'=>[], 'body'=>string] - * or null if termination request or invalid context. - */ - public function acceptRequest(): ?array - { - $body = $this->getWorker()->receive($ctx); - if (empty($body) && empty($ctx)) { - // termination request - return null; - } - - $ctx = json_decode($ctx, true); - if ($ctx === null) { - // invalid context - return null; - } - - return ['ctx' => $ctx, 'body' => $body]; - } - - /** - * Send response to the application server. - * - * @param int $status Http status code - * @param string $body Body of response - * @param string[][] $headers An associative array of the message's headers. Each - * key MUST be a header name, and each value MUST be an array of strings - * for that header. - */ - public function respond(int $status, string $body, array $headers = []): void - { - if (empty($headers)) { - // this is required to represent empty header set as map and not as array - $headers = new \stdClass(); - } - - $this->getWorker()->send( - $body, - (string) json_encode(['status' => $status, 'headers' => $headers]) - ); - } -} diff --git a/src/Logger/.empty b/src/Logger/.empty new file mode 100644 index 00000000..e69de29b diff --git a/src/Metrics.php b/src/Metrics.php deleted file mode 100755 index d6b6e1da..00000000 --- a/src/Metrics.php +++ /dev/null @@ -1,80 +0,0 @@ -rpc = $rpc; - } - - /** - * @inheritDoc - */ - public function add(string $name, float $value, array $labels = []): void - { - try { - $this->rpc->call('metrics.Add', compact('name', 'value', 'labels')); - } catch (RPCException $e) { - throw new MetricException($e->getMessage(), $e->getCode(), $e); - } - } - - /** - * @inheritDoc - */ - public function sub(string $name, float $value, array $labels = []): void - { - try { - $this->rpc->call('metrics.Sub', compact('name', 'value', 'labels')); - } catch (RPCException $e) { - throw new MetricException($e->getMessage(), $e->getCode(), $e); - } - } - - /** - * @inheritDoc - */ - public function observe(string $name, float $value, array $labels = []): void - { - try { - $this->rpc->call('metrics.Observe', compact('name', 'value', 'labels')); - } catch (RPCException $e) { - throw new MetricException($e->getMessage(), $e->getCode(), $e); - } - } - - /** - * @inheritDoc - */ - public function set(string $name, float $value, array $labels = []): void - { - try { - $this->rpc->call('metrics.Set', compact('name', 'value', 'labels')); - } catch (RPCException $e) { - throw new MetricException($e->getMessage(), $e->getCode(), $e); - } - } -} diff --git a/src/Metrics/Metrics.php b/src/Metrics/Metrics.php new file mode 100644 index 00000000..d6b6e1da --- /dev/null +++ b/src/Metrics/Metrics.php @@ -0,0 +1,80 @@ +rpc = $rpc; + } + + /** + * @inheritDoc + */ + public function add(string $name, float $value, array $labels = []): void + { + try { + $this->rpc->call('metrics.Add', compact('name', 'value', 'labels')); + } catch (RPCException $e) { + throw new MetricException($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * @inheritDoc + */ + public function sub(string $name, float $value, array $labels = []): void + { + try { + $this->rpc->call('metrics.Sub', compact('name', 'value', 'labels')); + } catch (RPCException $e) { + throw new MetricException($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * @inheritDoc + */ + public function observe(string $name, float $value, array $labels = []): void + { + try { + $this->rpc->call('metrics.Observe', compact('name', 'value', 'labels')); + } catch (RPCException $e) { + throw new MetricException($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * @inheritDoc + */ + public function set(string $name, float $value, array $labels = []): void + { + try { + $this->rpc->call('metrics.Set', compact('name', 'value', 'labels')); + } catch (RPCException $e) { + throw new MetricException($e->getMessage(), $e->getCode(), $e); + } + } +} diff --git a/src/Metrics/MetricsInterface.php b/src/Metrics/MetricsInterface.php new file mode 100644 index 00000000..ec2009b0 --- /dev/null +++ b/src/Metrics/MetricsInterface.php @@ -0,0 +1,64 @@ +httpClient = new HttpClient($worker); - $this->requestFactory = $requestFactory ?? new Diactoros\ServerRequestFactory(); - $this->streamFactory = $streamFactory ?? new Diactoros\StreamFactory(); - $this->uploadsFactory = $uploadsFactory ?? new Diactoros\UploadedFileFactory(); - $this->originalServer = $_SERVER; - } - - /** - * @return Worker - */ - public function getWorker(): Worker - { - return $this->httpClient->getWorker(); - } - - /** - * @return ServerRequestInterface|null - */ - public function acceptRequest(): ?ServerRequestInterface - { - $rawRequest = $this->httpClient->acceptRequest(); - if ($rawRequest === null) { - return null; - } - - $_SERVER = $this->configureServer($rawRequest['ctx']); - - $request = $this->requestFactory->createServerRequest( - $rawRequest['ctx']['method'], - $rawRequest['ctx']['uri'], - $_SERVER - ); - - parse_str($rawRequest['ctx']['rawQuery'], $query); - - $request = $request - ->withProtocolVersion(static::fetchProtocolVersion($rawRequest['ctx']['protocol'])) - ->withCookieParams($rawRequest['ctx']['cookies']) - ->withQueryParams($query) - ->withUploadedFiles($this->wrapUploads($rawRequest['ctx']['uploads'])); - - foreach ($rawRequest['ctx']['attributes'] as $name => $value) { - $request = $request->withAttribute($name, $value); - } - - foreach ($rawRequest['ctx']['headers'] as $name => $value) { - $request = $request->withHeader($name, $value); - } - - if ($rawRequest['ctx']['parsed']) { - return $request->withParsedBody(json_decode($rawRequest['body'], true)); - } - - if ($rawRequest['body'] !== null) { - return $request->withBody($this->streamFactory->createStream($rawRequest['body'])); - } - - return $request; - } - - /** - * Send response to the application server. - * - * @param ResponseInterface $response - */ - public function respond(ResponseInterface $response): void - { - $this->httpClient->respond( - $response->getStatusCode(), - $response->getBody()->__toString(), - $response->getHeaders() - ); - } - - /** - * Returns altered copy of _SERVER variable. Sets ip-address, - * request-time and other values. - * - * @param mixed[] $ctx - * @return mixed[] - */ - protected function configureServer(array $ctx): array - { - $server = $this->originalServer; - - $server['REQUEST_URI'] = $ctx['uri']; - $server['REQUEST_TIME'] = time(); - $server['REQUEST_TIME_FLOAT'] = microtime(true); - $server['REMOTE_ADDR'] = $ctx['attributes']['ipAddress'] ?? $ctx['remoteAddr'] ?? '127.0.0.1'; - $server['REQUEST_METHOD'] = $ctx['method']; - - $server['HTTP_USER_AGENT'] = ''; - foreach ($ctx['headers'] as $key => $value) { - $key = strtoupper(str_replace('-', '_', $key)); - if (\in_array($key, ['CONTENT_TYPE', 'CONTENT_LENGTH'])) { - $server[$key] = implode(', ', $value); - } else { - $server['HTTP_' . $key] = implode(', ', $value); - } - } - - return $server; - } - - /** - * Wraps all uploaded files with UploadedFile. - * - * @param array[] $files - * - * @return UploadedFileInterface[]|mixed[] - */ - private function wrapUploads($files): array - { - if (empty($files)) { - return []; - } - - $result = []; - foreach ($files as $index => $f) { - if (!isset($f['name'])) { - $result[$index] = $this->wrapUploads($f); - continue; - } - - if (UPLOAD_ERR_OK === $f['error']) { - $stream = $this->streamFactory->createStreamFromFile($f['tmpName']); - } else { - $stream = $this->streamFactory->createStream(); - } - - $result[$index] = $this->uploadsFactory->createUploadedFile( - $stream, - $f['size'], - $f['error'], - $f['name'], - $f['mime'] - ); - } - - return $result; - } - - /** - * Normalize HTTP protocol version to valid values - * - * @param string $version - * @return string - */ - private static function fetchProtocolVersion(string $version): string - { - $v = substr($version, 5); - - if ($v === '2.0') { - return '2'; - } - - // Fallback for values outside of valid protocol versions - if (!in_array($v, static::$allowedVersions, true)) { - return '1.1'; - } - - return $v; - } -} diff --git a/src/WorkerInterface.php b/src/WorkerInterface.php new file mode 100644 index 00000000..e69de29b -- cgit v1.2.3 From 126026f11f9b0108d80a3eb46097aabf9b31aa05 Mon Sep 17 00:00:00 2001 From: Wolfy-J Date: Wed, 28 Oct 2020 13:03:32 +0300 Subject: - added RPC logging --- plugins/rpc/config.go | 6 ++--- plugins/rpc/rpc.go | 67 +++++++++++++++++++++++++++------------------------ 2 files changed, 39 insertions(+), 34 deletions(-) diff --git a/plugins/rpc/config.go b/plugins/rpc/config.go index 719fd5e3..1a599695 100755 --- a/plugins/rpc/config.go +++ b/plugins/rpc/config.go @@ -8,7 +8,7 @@ import ( "github.com/spiral/roadrunner/v2/util" ) -// Config defines RPC service config. +// Config defines RPC service cfg. type Config struct { // Listen string Listen string @@ -17,14 +17,14 @@ type Config struct { Disabled bool } -// InitDefaults allows to init blank config with pre-defined set of default values. +// InitDefaults allows to init blank cfg with pre-defined set of default values. func (c *Config) InitDefaults() { if c.Listen == "" { c.Listen = "tcp://127.0.0.1:6001" } } -// Valid returns nil if config is valid. +// Valid returns nil if cfg is valid. func (c *Config) Valid() error { if dsn := strings.Split(c.Listen, "://"); len(dsn) != 2 { return errors.New("invalid socket DSN (tcp://:6001, unix://file.sock)") diff --git a/plugins/rpc/rpc.go b/plugins/rpc/rpc.go index 0f6c9753..894c89d8 100755 --- a/plugins/rpc/rpc.go +++ b/plugins/rpc/rpc.go @@ -1,6 +1,7 @@ package rpc import ( + "go.uber.org/zap" "net/rpc" "github.com/spiral/endure" @@ -20,65 +21,70 @@ type RPCPluggable interface { // ServiceName contains default service name. const ServiceName = "rpc" -type services struct { - service interface{} - name string -} - // Service is RPC service. type Service struct { + cfg Config + log *zap.Logger rpc *rpc.Server - services []services - config Config + services []RPCPluggable close chan struct{} } // Init rpc service. Must return true if service is enabled. -func (s *Service) Init(cfg config.Provider) error { +func (s *Service) Init(cfg config.Provider, log *zap.Logger) error { if !cfg.Has(ServiceName) { return errors.E(errors.Disabled) } - err := cfg.UnmarshalKey(ServiceName, &s.config) + err := cfg.UnmarshalKey(ServiceName, &s.cfg) if err != nil { return err } - s.config.InitDefaults() + s.cfg.InitDefaults() - if s.config.Disabled { + if s.cfg.Disabled { return errors.E(errors.Disabled) } - return s.config.Valid() -} + s.log = log -// Name contains service name. -func (s *Service) Name() string { - return ServiceName + return s.cfg.Valid() } // Serve serves the service. func (s *Service) Serve() chan error { - s.close = make(chan struct{}, 1) errCh := make(chan error, 1) + s.close = make(chan struct{}, 1) s.rpc = rpc.NewServer() + names := make([]string, 0, len(s.services)) + // Attach all services for i := 0; i < len(s.services); i++ { - err := s.Register(s.services[i].name, s.services[i].service) + svc, err := s.services[i].RPCService() if err != nil { errCh <- errors.E(errors.Op("register service"), err) return errCh } + + err = s.Register(s.services[i].Name(), svc) + if err != nil { + errCh <- errors.E(errors.Op("register service"), err) + return errCh + } + + names = append(names, s.services[i].Name()) } - ln, err := s.config.Listener() + ln, err := s.cfg.Listener() if err != nil { errCh <- err return errCh } + s.log.Debug("Started RPC service", zap.String("address", s.cfg.Listen), zap.Any("services", names)) + go func() { for { select { @@ -109,22 +115,21 @@ func (s *Service) Stop() error { return nil } +// Name contains service name. +func (s *Service) Name() string { + return ServiceName +} + +// Depends declares services to collect for RPC. func (s *Service) Depends() []interface{} { return []interface{}{ - s.RegisterService, + s.RegisterPlugin, } } -func (s *Service) RegisterService(p RPCPluggable) error { - service, err := p.RPCService() - if err != nil { - return err - } - - s.services = append(s.services, services{ - service: service, - name: p.Name(), - }) +// RegisterPlugin registers RPC service plugin. +func (s *Service) RegisterPlugin(p RPCPluggable) error { + s.services = append(s.services, p) return nil } @@ -146,7 +151,7 @@ func (s *Service) Register(name string, svc interface{}) error { // Client creates new RPC client. func (s *Service) Client() (*rpc.Client, error) { - conn, err := s.config.Dialer() + conn, err := s.cfg.Dialer() if err != nil { return nil, err } -- cgit v1.2.3 From 5d87fa2666a5b4e683816bd45fbe08f50cd84af6 Mon Sep 17 00:00:00 2001 From: Wolfy-J Date: Wed, 28 Oct 2020 13:05:21 +0300 Subject: - added RPC logging --- plugins/rpc/rpc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/rpc/rpc.go b/plugins/rpc/rpc.go index 894c89d8..dc228847 100755 --- a/plugins/rpc/rpc.go +++ b/plugins/rpc/rpc.go @@ -83,7 +83,7 @@ func (s *Service) Serve() chan error { return errCh } - s.log.Debug("Started RPC service", zap.String("address", s.cfg.Listen), zap.Any("services", names)) + s.log.Debug("Started RPC service", zap.String("Address", s.cfg.Listen), zap.Any("Services", names)) go func() { for { -- cgit v1.2.3 From a9ddea1855ffda6f6388fc91223b8c63ed48b32f Mon Sep 17 00:00:00 2001 From: Wolfy-J Date: Wed, 28 Oct 2020 13:05:31 +0300 Subject: - added RPC logging --- plugins/rpc/rpc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/rpc/rpc.go b/plugins/rpc/rpc.go index dc228847..894c89d8 100755 --- a/plugins/rpc/rpc.go +++ b/plugins/rpc/rpc.go @@ -83,7 +83,7 @@ func (s *Service) Serve() chan error { return errCh } - s.log.Debug("Started RPC service", zap.String("Address", s.cfg.Listen), zap.Any("Services", names)) + s.log.Debug("Started RPC service", zap.String("address", s.cfg.Listen), zap.Any("services", names)) go func() { for { -- cgit v1.2.3 From d6ceb16a9a165764739137de6a2b621685bb8ac3 Mon Sep 17 00:00:00 2001 From: Wolfy-J Date: Wed, 28 Oct 2020 13:26:00 +0300 Subject: - new coloring strategy for names --- plugins/logger/config.go | 7 ++++- plugins/logger/encoder.go | 65 ++++++++++++++++++++++++++++++++++++++++++++ plugins/logger/zap_logger.go | 38 +++++--------------------- 3 files changed, 78 insertions(+), 32 deletions(-) create mode 100644 plugins/logger/encoder.go diff --git a/plugins/logger/config.go b/plugins/logger/config.go index 12badade..4e9f1220 100644 --- a/plugins/logger/config.go +++ b/plugins/logger/config.go @@ -1,9 +1,14 @@ package logger type Config struct { - Squash bool + Default LoggerConfig + + Suppress bool + Channels map[string]LoggerConfig } type LoggerConfig struct { + // Level to report messages from. + Level string } diff --git a/plugins/logger/encoder.go b/plugins/logger/encoder.go new file mode 100644 index 00000000..3eef191b --- /dev/null +++ b/plugins/logger/encoder.go @@ -0,0 +1,65 @@ +package logger + +import ( + "github.com/fatih/color" + "go.uber.org/zap/zapcore" + "hash/fnv" + "strings" + "time" +) + +var colorMap = []func(string, ...interface{}) string{ + color.HiYellowString, + color.HiGreenString, + color.HiBlueString, + color.HiRedString, + color.HiCyanString, + color.HiMagentaString, +} + +// ColoredLevelEncoder colorizes log levels. +func ColoredLevelEncoder(level zapcore.Level, enc zapcore.PrimitiveArrayEncoder) { + switch level { + case zapcore.DebugLevel: + enc.AppendString(color.HiWhiteString(level.CapitalString())) + case zapcore.InfoLevel: + enc.AppendString(color.HiCyanString(level.CapitalString())) + case zapcore.WarnLevel: + enc.AppendString(color.HiYellowString(level.CapitalString())) + case zapcore.ErrorLevel, zapcore.DPanicLevel: + enc.AppendString(color.HiRedString(level.CapitalString())) + case zapcore.PanicLevel, zapcore.FatalLevel: + enc.AppendString(color.HiMagentaString(level.CapitalString())) + } +} + +// ColoredNameEncoder colorizes service names. +func ColoredNameEncoder(s string, enc zapcore.PrimitiveArrayEncoder) { + if len(s) < 12 { + s = s + strings.Repeat(" ", 12-len(s)) + } + + enc.AppendString(color.HiGreenString(s)) +} + +// ColoredHashedNameEncoder colorizes service names and assigns different colors to different names. +func ColoredHashedNameEncoder(s string, enc zapcore.PrimitiveArrayEncoder) { + if len(s) < 12 { + s = s + strings.Repeat(" ", 12-len(s)) + } + + colorID := stringHash(s, len(colorMap)) + enc.AppendString(colorMap[colorID](s)) +} + +// UTCTimeEncoder encodes time into short UTC specific timestamp. +func UTCTimeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) { + enc.AppendString(t.UTC().Format("2006/01/02 15:04:05")) +} + +// returns string hash +func stringHash(name string, base int) int { + h := fnv.New32a() + h.Write([]byte(name)) + return int(h.Sum32()) % base +} diff --git a/plugins/logger/zap_logger.go b/plugins/logger/zap_logger.go index 747cbf77..e1986da3 100644 --- a/plugins/logger/zap_logger.go +++ b/plugins/logger/zap_logger.go @@ -1,13 +1,10 @@ package logger import ( - "github.com/fatih/color" "github.com/spiral/endure" "github.com/spiral/roadrunner/v2/plugins/config" "go.uber.org/zap" "go.uber.org/zap/zapcore" - "strings" - "time" ) // ServiceName declares service name. @@ -38,34 +35,13 @@ func (z *ZapLogger) Init(cfg config.Provider) (err error) { Level: zap.NewAtomicLevelAt(zap.DebugLevel), Encoding: "console", EncoderConfig: zapcore.EncoderConfig{ - MessageKey: "message", - LevelKey: "level", - TimeKey: "time", - NameKey: "name", - EncodeName: func(s string, enc zapcore.PrimitiveArrayEncoder) { - if len(s) < 12 { - s = s + strings.Repeat(" ", 12-len(s)) - } - - enc.AppendString(color.HiGreenString(s)) - }, - EncodeLevel: func(level zapcore.Level, enc zapcore.PrimitiveArrayEncoder) { - switch level { - case zapcore.DebugLevel: - enc.AppendString(color.HiWhiteString(level.CapitalString())) - case zapcore.InfoLevel: - enc.AppendString(color.HiCyanString(level.CapitalString())) - case zapcore.WarnLevel: - enc.AppendString(color.HiYellowString(level.CapitalString())) - case zapcore.ErrorLevel, zapcore.DPanicLevel: - enc.AppendString(color.HiRedString(level.CapitalString())) - case zapcore.PanicLevel, zapcore.FatalLevel: - enc.AppendString(color.HiMagentaString(level.CapitalString())) - } - }, - EncodeTime: func(t time.Time, enc zapcore.PrimitiveArrayEncoder) { - enc.AppendString(t.UTC().Format("2006/01/02 15:04:05")) - }, + MessageKey: "message", + LevelKey: "level", + TimeKey: "time", + NameKey: "name", + EncodeName: ColoredHashedNameEncoder, + EncodeLevel: ColoredLevelEncoder, + EncodeTime: UTCTimeEncoder, EncodeCaller: zapcore.ShortCallerEncoder, }, OutputPaths: []string{"stderr"}, -- cgit v1.2.3 From 39ed532b4e047ac1c0471c2b935065c89dfaecf1 Mon Sep 17 00:00:00 2001 From: Wolfy-J Date: Wed, 28 Oct 2020 14:38:29 +0300 Subject: - added the ability to suppress logs --- plugins/app/app.go | 7 +++- plugins/logger/config.go | 89 +++++++++++++++++++++++++++++++++++++++++--- plugins/logger/zap_logger.go | 67 ++++++++++++--------------------- 3 files changed, 113 insertions(+), 50 deletions(-) diff --git a/plugins/app/app.go b/plugins/app/app.go index 950d7791..434c955e 100644 --- a/plugins/app/app.go +++ b/plugins/app/app.go @@ -3,6 +3,7 @@ package app import ( "context" "fmt" + "go.uber.org/zap" "log" "os" "os/exec" @@ -29,16 +30,18 @@ type WorkerFactory interface { // App manages worker type App struct { cfg Config + log *zap.Logger factory roadrunner.Factory } // Init application provider. -func (app *App) Init(cfg config.Provider) error { +func (app *App) Init(cfg config.Provider, log *zap.Logger) error { err := cfg.UnmarshalKey(ServiceName, &app.cfg) if err != nil { return err } app.cfg.InitDefaults() + app.log = log return nil } @@ -57,6 +60,8 @@ func (app *App) Serve() chan error { errCh <- errors.E(errors.Op("init factory"), err) } + app.log.Debug("Started worker factory", zap.Any("relay", app.cfg.Relay), zap.Any("command", app.cfg.Command)) + return errCh } diff --git a/plugins/logger/config.go b/plugins/logger/config.go index 4e9f1220..ba0530d2 100644 --- a/plugins/logger/config.go +++ b/plugins/logger/config.go @@ -1,14 +1,91 @@ package logger +import ( + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + "strings" +) + +// ChannelConfig configures loggers per channel. +type ChannelConfig struct { + // Dedicated channels per logger. By default logger allocated via named logger. + Channels map[string]Config `json:"channels" yaml:"channels"` +} + type Config struct { - Default LoggerConfig + // Mode configures logger based on some default template (development, production, off). + Mode string `json:"mode" yaml:"mode"` + + // Level is the minimum enabled logging level. Note that this is a dynamic + // level, so calling ChannelConfig.Level.SetLevel will atomically change the log + // level of all loggers descended from this config. + Level string `json:"level" yaml:"level"` + + // Encoding sets the logger's encoding. Valid values are "json" and + // "console", as well as any third-party encodings registered via + // RegisterEncoder. + Encoding string `json:"encoding" yaml:"encoding"` - Suppress bool + // Output is a list of URLs or file paths to write logging output to. + // See Open for details. + Output []string `json:"output" yaml:"output"` - Channels map[string]LoggerConfig + // ErrorOutput is a list of URLs to write internal logger errors to. + // The default is standard error. + // + // Note that this setting only affects internal errors; for sample code that + // sends error-level logs to a different location from info- and debug-level + // logs, see the package-level AdvancedConfiguration example. + ErrorOutput []string `json:"errorOutput" yaml:"errorOutput"` } -type LoggerConfig struct { - // Level to report messages from. - Level string +// ZapConfig converts config into Zap configuration. +func (cfg *Config) BuildLogger() (*zap.Logger, error) { + var zCfg zap.Config + switch strings.ToLower(cfg.Mode) { + case "off", "none": + return zap.NewNop(), nil + case "production": + zCfg = zap.NewProductionConfig() + case "development": + zCfg = zap.NewDevelopmentConfig() + default: + zCfg = zap.Config{ + Level: zap.NewAtomicLevelAt(zap.DebugLevel), + Encoding: "console", + EncoderConfig: zapcore.EncoderConfig{ + MessageKey: "message", + LevelKey: "level", + TimeKey: "time", + NameKey: "name", + EncodeName: ColoredHashedNameEncoder, + EncodeLevel: ColoredLevelEncoder, + EncodeTime: UTCTimeEncoder, + EncodeCaller: zapcore.ShortCallerEncoder, + }, + OutputPaths: []string{"stderr"}, + ErrorOutputPaths: []string{"stderr"}, + } + } + + if cfg.Level != "" { + level := zap.NewAtomicLevel() + if err := level.UnmarshalText([]byte(cfg.Level)); err == nil { + zCfg.Level = level + } + } + + if cfg.Encoding != "" { + zCfg.Encoding = cfg.Encoding + } + + if len(cfg.Output) != 0 { + zCfg.OutputPaths = cfg.Output + } + + if len(cfg.ErrorOutput) != 0 { + zCfg.ErrorOutputPaths = cfg.ErrorOutput + } + + return zCfg.Build() } diff --git a/plugins/logger/zap_logger.go b/plugins/logger/zap_logger.go index e1986da3..8c1739f2 100644 --- a/plugins/logger/zap_logger.go +++ b/plugins/logger/zap_logger.go @@ -4,7 +4,6 @@ import ( "github.com/spiral/endure" "github.com/spiral/roadrunner/v2/plugins/config" "go.uber.org/zap" - "go.uber.org/zap/zapcore" ) // ServiceName declares service name. @@ -20,68 +19,50 @@ type LogFactory interface { // ZapLogger manages zap logger. type ZapLogger struct { - base *zap.Logger - cfg Config + base *zap.Logger + cfg Config + channels ChannelConfig } +// Init logger service. func (z *ZapLogger) Init(cfg config.Provider) (err error) { err = cfg.UnmarshalKey(ServiceName, &z.cfg) if err != nil { return err } - if z.base == nil { - cfg := zap.Config{ - Level: zap.NewAtomicLevelAt(zap.DebugLevel), - Encoding: "console", - EncoderConfig: zapcore.EncoderConfig{ - MessageKey: "message", - LevelKey: "level", - TimeKey: "time", - NameKey: "name", - EncodeName: ColoredHashedNameEncoder, - EncodeLevel: ColoredLevelEncoder, - EncodeTime: UTCTimeEncoder, - EncodeCaller: zapcore.ShortCallerEncoder, - }, - OutputPaths: []string{"stderr"}, - ErrorOutputPaths: []string{"stderr"}, - } - - z.base, err = cfg.Build() - if err != nil { - return err - } + err = cfg.UnmarshalKey(ServiceName, &z.channels) + if err != nil { + return err } - return nil + z.base, err = z.cfg.BuildLogger() + return err +} + +// DefaultLogger returns default logger. +func (z *ZapLogger) DefaultLogger() (*zap.Logger, error) { + return z.base, nil } -// GlobalLogger returns global log instance. -func (z *ZapLogger) GlobalLogger() *zap.Logger { - return z.base +// NamedLogger returns logger dedicated to the specific channel. Similar to Named() but also reads the core params. +func (z *ZapLogger) NamedLogger(name string) (*zap.Logger, error) { + if cfg, ok := z.channels.Channels[name]; ok { + return cfg.BuildLogger() + } + + return z.base.Named(name), nil } // NamedLogger returns logger dedicated to the specific channel. Similar to Named() but also reads the core params. -func (z *ZapLogger) NamedLogger(name string) *zap.Logger { - // todo: automatically configure - return z.base.Named(name) +func (z *ZapLogger) ServiceLogger(n endure.Named) (*zap.Logger, error) { + return z.NamedLogger(n.Name()) } // Provides declares factory methods. func (z *ZapLogger) Provides() []interface{} { return []interface{}{ z.DefaultLogger, - z.AllocateLogger, + z.ServiceLogger, } } - -// AllocateLogger allocates logger for the service. -func (z *ZapLogger) AllocateLogger(n endure.Named) (*zap.Logger, error) { - return z.NamedLogger(n.Name()), nil -} - -// DefaultLogger returns default logger. -func (z *ZapLogger) DefaultLogger() (*zap.Logger, error) { - return z.GlobalLogger(), nil -} -- cgit v1.2.3 From 30bfcc3e4852d87bb9fe17ff134b0a7ece1fcae0 Mon Sep 17 00:00:00 2001 From: Wolfy-J Date: Wed, 28 Oct 2020 14:39:19 +0300 Subject: - better logging --- plugins/app/app.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/app/app.go b/plugins/app/app.go index 434c955e..ebb42631 100644 --- a/plugins/app/app.go +++ b/plugins/app/app.go @@ -60,7 +60,7 @@ func (app *App) Serve() chan error { errCh <- errors.E(errors.Op("init factory"), err) } - app.log.Debug("Started worker factory", zap.Any("relay", app.cfg.Relay), zap.Any("command", app.cfg.Command)) + app.log.Info("Started worker factory", zap.Any("relay", app.cfg.Relay), zap.Any("command", app.cfg.Command)) return errCh } -- cgit v1.2.3 From a8e31d57147252b0ef28237bf3094d7f5af01f5e Mon Sep 17 00:00:00 2001 From: Wolfy-J Date: Wed, 28 Oct 2020 14:41:32 +0300 Subject: - fix cfg comment --- plugins/rpc/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/rpc/config.go b/plugins/rpc/config.go index 1a599695..802ed5ba 100755 --- a/plugins/rpc/config.go +++ b/plugins/rpc/config.go @@ -8,7 +8,7 @@ import ( "github.com/spiral/roadrunner/v2/util" ) -// Config defines RPC service cfg. +// Config defines RPC service config. type Config struct { // Listen string Listen string -- cgit v1.2.3 From 9f6e68dd5ea97b6b490e3a76e0a01b13a0ce414b Mon Sep 17 00:00:00 2001 From: Wolfy-J Date: Wed, 28 Oct 2020 14:44:05 +0300 Subject: - fix PHP typo --- src/Http/PSR7Client.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Http/PSR7Client.php b/src/Http/PSR7Client.php index 94a9457b..777dd891 100644 --- a/src/Http/PSR7Client.php +++ b/src/Http/PSR7Client.php @@ -12,7 +12,7 @@ namespace Spiral\RoadRunner; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestFactoryInterface; use Psr\Http\Message\ServerRequestInterface; -use Psr\Http\Message\StreamF actoryInterface; +use Psr\Http\Message\StreamFactoryInterface; use Psr\Http\Message\UploadedFileFactoryInterface; use Psr\Http\Message\UploadedFileInterface; -- cgit v1.2.3 From 3e2b12f2e9218d6251f6e87dc20527a9c11853e7 Mon Sep 17 00:00:00 2001 From: Wolfy-J Date: Wed, 28 Oct 2020 14:46:57 +0300 Subject: - cs fix --- plugins/logger/encoder.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/logger/encoder.go b/plugins/logger/encoder.go index 3eef191b..30ae2400 100644 --- a/plugins/logger/encoder.go +++ b/plugins/logger/encoder.go @@ -36,7 +36,7 @@ func ColoredLevelEncoder(level zapcore.Level, enc zapcore.PrimitiveArrayEncoder) // ColoredNameEncoder colorizes service names. func ColoredNameEncoder(s string, enc zapcore.PrimitiveArrayEncoder) { if len(s) < 12 { - s = s + strings.Repeat(" ", 12-len(s)) + s += strings.Repeat(" ", 12-len(s)) } enc.AppendString(color.HiGreenString(s)) @@ -45,7 +45,7 @@ func ColoredNameEncoder(s string, enc zapcore.PrimitiveArrayEncoder) { // ColoredHashedNameEncoder colorizes service names and assigns different colors to different names. func ColoredHashedNameEncoder(s string, enc zapcore.PrimitiveArrayEncoder) { if len(s) < 12 { - s = s + strings.Repeat(" ", 12-len(s)) + s += strings.Repeat(" ", 12-len(s)) } colorID := stringHash(s, len(colorMap)) -- cgit v1.2.3 From 42cb82dbca79fcb47633b203d2d4ea9b0a59a176 Mon Sep 17 00:00:00 2001 From: Wolfy-J Date: Wed, 28 Oct 2020 14:56:12 +0300 Subject: - go fmt --- plugins/logger/config.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/logger/config.go b/plugins/logger/config.go index ba0530d2..9248eb3a 100644 --- a/plugins/logger/config.go +++ b/plugins/logger/config.go @@ -87,5 +87,7 @@ func (cfg *Config) BuildLogger() (*zap.Logger, error) { zCfg.ErrorOutputPaths = cfg.ErrorOutput } + // todo: https://github.com/uber-go/zap/blob/master/FAQ.md#does-zap-support-log-rotation + return zCfg.Build() } -- cgit v1.2.3 From 2f2a0f90d0ff5ef773f17451bfa2c679604562f7 Mon Sep 17 00:00:00 2001 From: Wolfy-J Date: Wed, 28 Oct 2020 15:38:37 +0300 Subject: - fix cfg typos --- plugins/rpc/config.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/rpc/config.go b/plugins/rpc/config.go index 802ed5ba..719fd5e3 100755 --- a/plugins/rpc/config.go +++ b/plugins/rpc/config.go @@ -17,14 +17,14 @@ type Config struct { Disabled bool } -// InitDefaults allows to init blank cfg with pre-defined set of default values. +// InitDefaults allows to init blank config with pre-defined set of default values. func (c *Config) InitDefaults() { if c.Listen == "" { c.Listen = "tcp://127.0.0.1:6001" } } -// Valid returns nil if cfg is valid. +// Valid returns nil if config is valid. func (c *Config) Valid() error { if dsn := strings.Split(c.Listen, "://"); len(dsn) != 2 { return errors.New("invalid socket DSN (tcp://:6001, unix://file.sock)") -- cgit v1.2.3 From 175c02e501a3b5110f8882599d5d033fde5bf81b Mon Sep 17 00:00:00 2001 From: Valery Piashchynski Date: Wed, 28 Oct 2020 15:57:45 +0300 Subject: goimport-ed files --- plugins/logger/config.go | 3 ++- plugins/logger/encoder.go | 5 +++-- plugins/rpc/rpc.go | 3 ++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/plugins/logger/config.go b/plugins/logger/config.go index 9248eb3a..f7a5742c 100644 --- a/plugins/logger/config.go +++ b/plugins/logger/config.go @@ -1,9 +1,10 @@ package logger import ( + "strings" + "go.uber.org/zap" "go.uber.org/zap/zapcore" - "strings" ) // ChannelConfig configures loggers per channel. diff --git a/plugins/logger/encoder.go b/plugins/logger/encoder.go index 30ae2400..66cd84f1 100644 --- a/plugins/logger/encoder.go +++ b/plugins/logger/encoder.go @@ -1,11 +1,12 @@ package logger import ( - "github.com/fatih/color" - "go.uber.org/zap/zapcore" "hash/fnv" "strings" "time" + + "github.com/fatih/color" + "go.uber.org/zap/zapcore" ) var colorMap = []func(string, ...interface{}) string{ diff --git a/plugins/rpc/rpc.go b/plugins/rpc/rpc.go index 894c89d8..d272fc72 100755 --- a/plugins/rpc/rpc.go +++ b/plugins/rpc/rpc.go @@ -1,9 +1,10 @@ package rpc import ( - "go.uber.org/zap" "net/rpc" + "go.uber.org/zap" + "github.com/spiral/endure" "github.com/spiral/endure/errors" "github.com/spiral/goridge/v2" -- cgit v1.2.3