Giter Site home page Giter Site logo

netlogix.sentry's Introduction

Netlogix.Sentry

About

This package provides a Flow integration for the sentry.io PHP SDK. Some basic information about the Flow application is added to the sentry Event by default, but you can easily configure and extend this package to fit your needs.

Installation

composer require netlogix/sentry

Currently the following Flow versions are supported:

  • ^7.3
  • ^8.0

Setup

The sentry DSN Client Key has to be configured. Get it from your project settings (SDK Setup -> Client Keys (DSN)).

Netlogix:
  Sentry:
    dsn: 'https://[email protected]/123456789'

Then simply run ./flow sentry:test to log an exception to sentry. While this is technically all you have to do, you might want to adjust the providers - see below.

Configuration

This package allows you to configure which data should be added to the sentry event by changing the providers for each scope. Currently, the available scopes are environment, extra, release, tags and user.

Providers can be sorted using the PositionalArraySorter position strings. For the scopes extra, tags and user, all data provided will be merged together. The scopes environment and release only support a single value (you can still configure more than one provider, but the last one wins).

Netlogix:
  Sentry:
    scope:
      extra: [ ]

      release:
        # If you don't need a specific order, you can simply set the provider to true
        'Netlogix\Sentry\Scope\Release\PathPattern': true

      tags:
        # Numerical order can be used
        'Netlogix\Sentry\Scope\Tags\FlowEnvironment': '10'
        'Your\Custom\TagProvider': '20'

      user:
        'Your\Custom\UserProvider': 'start 1000'
        # If you don't want to add the currently authenticated Flow Account to the Event, simply disable the provider
        'Netlogix\Sentry\Scope\User\FlowAccount': false

Environments

The sentry SDK will search for the environment variable SENTRY_ENVIRONMENT and use it's value as the current environment. This is still the default, however you can configure the Netlogix\Sentry\Scope\Environment\FlowSettings provider to use a different value:

Netlogix:
  Sentry:
    environment:
      setting: '%env:SENTRY_ENVIRONMENT%'

Release tracking

You can use the Netlogix\Sentry\Scope\Release\PathPattern ReleaseProvider to extract your current release from the app directory. By default, the configured pathPattern is matched against the FLOW_PATH_ROOT constant:

Netlogix:
  Sentry:

    # Used by Netlogix\Sentry\Scope\Release\PathPattern
    release:
      # Path to use for extraction of release
      pathToMatch: '%FLOW_PATH_ROOT%'

      # Pattern to extract current release from file path
      # This pattern is matched against pathToMatch
      pathPattern: '~/releases/(\d{14})$~'

You can also use the Netlogix\Sentry\Scope\Release\FlowSettings to set the Release through Flow Configuration (Netlogix.Sentry.release.setting, set to %env:SENTRY_RELEASE% by default).

Custom Providers

For each scope, you can implement your own providers. Each scope requires it's own interface:

  • Scope environment => Netlogix\Sentry\Scope\Environment\EnvironmentProvider
  • Scope extra => Netlogix\Sentry\Scope\Extra\ExtraProvider
  • Scope release => Netlogix\Sentry\Scope\Release\ReleaseProvider
  • Scope tags => Netlogix\Sentry\Scope\Tags\TagProvider
  • Scope user => Netlogix\Sentry\Scope\User\UserProvider

Then simply add them to the configuration.

If you need access to the thrown exception, you can check Netlogix\Sentry\Scope\ScopeProvider::getCurrentThrowable():

<?php

namespace Netlogix\Sentry\Scope\Extra;

use Neos\Flow\Annotations as Flow;
use Neos\Flow\Exception as FlowException;
use Netlogix\Sentry\Scope\ScopeProvider;

/**
 * @Flow\Scope("singleton")
 */
final class ReferenceCodeProvider implements ExtraProvider
{

    private ScopeProvider $scopeProvider;

    public function __construct(ScopeProvider $scopeProvider)
    {
        $this->scopeProvider = $scopeProvider;
    }

    public function getExtra(): array
    {
        $throwable = $this->scopeProvider->getCurrentThrowable();

        if (!$throwable instanceof FlowException) {
            return [];
        }

        return ['referenceCode' => $throwable->getReferenceCode()];
    }

}

Manually logging exceptions to sentry

If you need to manually send exceptions to sentry (inside a catch block for example), you can use the Netlogix\Sentry\ThrowableStorage\SentryStorage:

<?php

use Neos\Flow\Annotations as Flow;
use Netlogix\Sentry\ThrowableStorage\SentryStorage;

class LoggingManually {

    /**
     * @Flow\Inject
     * @var SentryStorage
     */
    protected $sentryStorage;

    public function log(): void {
        $exception = new \RuntimeException('foo', 1612114936);

        $this->sentryStorage->logThrowable($exception, ['some' => ['additional', 'data']]);
    }

}

Ignoring exceptions

If you need to skip sending a specific exception to sentry, you can use Flow's renderingGroups. Simply create one that matches your exception and set logException to false:

Neos:
  Flow:
    error:
      exceptionHandler:
        renderingGroups:

          ignoredExceptions:
            matchingStatusCodes: [ 418 ]
            matchingExceptionClassNames: [ 'Your\Ignored\Exception' ]
            # It is also possible to match against \Throwable::getCode(). Please note that this is not a Flow feature.
            # Check \Netlogix\Sentry\ExceptionHandler\ExceptionRenderingOptionsResolver::resolveRenderingGroup() for more info
            # matchingExceptionCodes: [1638880375]
            options:
              logException: false

Please note that this also disables logging of this exception to Data/Logs/Exceptions.

Encrypt POST payload

By default, the array of POST payload data is transported to the sentry server "as is".

When encryption is enabled and a valid rsa key fingerprint is set, the POST payload is stripped and replaced by an RSA encrypted string.

Netlogix:
  Sentry:

    privacy:
      encryptPostBody: true
      rsaKeyFingerprint: '6ff568ae0f9b44b69627e275accf163a'

POST data without encryption usually looks like this in sentry:

{
    "--some-form": {
        "__currentPage": 1,
        "__state": "TmV0bG9naXguU2VudHJ5IHN0YXRlIGRhdGE=",
        "__trustedProperties": "[Filtered]",
        "firstName": "John",
        "lastName": "Doe",
        "birthday": "2021-01-01",
        "email": "[email protected]",
        "message": "Lorem ipsum dolor sit amet"
    }
}

With encryption enabled it looks like this:

{
    "__ENCRYPTED__DATA__": {
        "encryptedData": "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2ljaSBlbGl0LCBzZWQgZWl1c21vZCB0ZW1wb3IgaW5jaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWduYSBhbGlxdWEuIFV0IGVuaW0gYWQgbWluaW0gdmVuaWFtLCBxdWlzIG5vc3RydWQgZXhlcmNpdGF0aW9u",
        "envelopeKey": "ZGVzZXJ1bnQgbW9sbGl0IGFuaW0gaWQgZXN0IGxhYm9ydW0=",
        "initializationVector": "QmxpbmR0ZXh0"
    }
}

There will be an additional sentry field "Encrypted POST Data" which contains a backlink to encrypt and show the original data.

In order for this to work, there must be an authentication provider in place that handels the Neos.Sentry controller.

If this package is used in conjunction with the neos/neos CMS, the neos backend authentication provider can be tasked with this job. See the code snippet below.

If this package is used without neos/neos, a custom privilege for policy Netlogix.Sentry:Backend.EncryptedPayload has to be configured.

Neos:
  Flow:
    security:
      authentication:
        providers:
          'Neos.Neos:Backend':
            requestPatterns:
              'Netlogix.Sentry:ShowEncryptedPayload':
                pattern: ControllerObjectName
                patternOptions:
                  controllerObjectNamePattern: 'Netlogix\Sentry\Controller\.*'

netlogix.sentry's People

Contributors

paxuclus avatar prgfx avatar saschanowak avatar stephanschuler avatar toni-bessel avatar tweis avatar

Stargazers

 avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

Forkers

mindscreen

netlogix.sentry's Issues

Add option to specify Environment

By default, sentry searches for the environment variable SENTRY_ENVIRONMENT. For projects without environment variables, it should be possible to set the environment through the settings.

Similar to the Settings.Release.yaml:

Netlogix:
  Sentry:
    environment:
      setting: '%env:SENTRY_ENVIRONMENT%'

We could then introduce a FlowSettings Provider for the Environment.

Since the default setting is %env:SENTRY_ENVIRONMENT%, this will also work for projects with environment variables.

Add compound ThrowableStorage so exceptions are also logged to Data/Logs/Exceptions

Currently, the default storage class is set to the SentryThrowableStorage, which disables the default FileStorage of Flow:

Neos:
  Flow:
    log:
      throwables:
        storageClass: Netlogix\Sentry\ThrowableStorage\SentryThrowableStorage

This could be solved by adding some sort of compound ThrowableStorage, that internally uses both, the FileStorage and SentryThrowableStorage.

Also while we're at it, it might make sense to rename the SentryThrowableStorage to just SentryStorage.

Integrate EventProcessor chain into ScopeProvider

Current situation:

The ScopeProvider has several "slots" of information, such as "environment", "tags", "release", "tags" and "user".

There's an individual chain of *Provider classes for each slot.
Every such class can add data.
Each provider is unaware of the data other providers contributed, as well as the data already present in the Sentry\Event during runtime. So those calls are more or less static, although they can depend on user input such as e.g. the currently logged in frontend user.

Obstacle:

  1. There is no way of overruling existing data by reading it from the Event object, manipulating it, and adding it back to the event.
    Real world example: Replace the POST payload with an encrypted version of it.

    1. Try and recreate the POST body exactly like Sentry did (by copying Sentry code because this part is private).
    2. Overwrite every POST body attribute with null, hoping to eliminate existing data.
    3. Encrypt and export in a new POST body attribute.
      This isn't particularly confidence inspiring because every Sentry update might change the way this data is named slightly without me knowing I'm pushing unencrypted data to Sentry again.
  2. Making changes in two slots at once isn't possible.
    The mentioned feature of encrypting POST body data should add a link to the neos backend, targeting a backend module where administrators can decrypt and review this data.
    This link should go into the "Extras" section, not into the POST body.

What should we do?

  • Introduce the concept of EventProcessors.
  • EventProcessors have a separate configuration section in the yaml file.
  • The EventProcessor should take an Event and update it or replace it entirely.
  • Make the NetlogixIntegraton walk through the chain of EventProcessors exactly where currently the ScopeProcessor is asked for collection slot data.
  • Move all ScopeProvider::collect* methods into individual *EventProcessor classes.

This should, from the perspective of yaml configuration and interfaces in the "Scope" folder, with no breaking change while adding a new layer of event manipulation capability.

Add tests

There should be some tests for the provider magic.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.