Next.js: Wie man Fehler abfängt und behandelt, um Protokolle auf der Serverseite zu melden

Erstellt am 2. Mai 2017  ·  74Kommentare  ·  Quelle: vercel/next.js

Hallo,
Ich bin in der Situation, in der wir Fehler sowohl auf der Server- als auch auf der Clientseite an das Sentry-Tool senden möchten.

Unsere App verwendet Express als benutzerdefinierten Server. Im Grunde erstellen wir eine Express-App, wenden einige Middleware an, delegieren aber den gesamten Job an das next.js-Handle:

  const app = nextJs({ dev: process.env.NODE_ENV !== 'production' });
  const handler = routes.getRequestHandler(app);
  const expressApp = express();

  ...
  ...

  expressApp.use(morgan('combined', { stream: logger.stream }));
  expressApp.use(statsdMiddleware);

  // Add security
  expressApp.use(helmet());

  // Sentry handler
  expressApp.use(sentry.requestHandler());

  // Load locale and translation messages
  expressApp.use(i18n);

  // Next.js handler
  expressApp.use(handler);

  // Sentry error handler.
  // MUST be placed before any other express error handler !!!
  expressApp.use(sentry.errorHandler());

Mit diesem Ansatz übernimmt next.js die Kontrolle über den Rendering-Prozess und jeder Fehler wird von next.js abgefangen und die einzige Möglichkeit, ihn zu verarbeiten, besteht darin, die Auslagerungsdatei _error.js überschreiben.

Innerhalb dieser _error.js Datei brauche ich eine universelle Möglichkeit, Fehler an Sentry zu melden. Derzeit gibt es zwei Bibliotheken ( raven für Knoten und raven-js Javascript). Das Problem ist, dass ich nicht beide importieren kann, weil raven für SSR funktioniert, aber fehlschlägt, wenn Webpack das Bundle erstellt, und auch raven-js aufgrund der XMLHTTPRequest-Abhängigkeit fehlschlägt.

Gibt es eine Möglichkeit, bei einem next.js-Fehler auf der Serverseite benachrichtigt zu werden?

story feature request

Hilfreichster Kommentar

Ich muss _unortodox_ Lösungen lieben

function installErrorHandler(app) {
  const _renderErrorToHTML = app.renderErrorToHTML.bind(app)
  const errorHandler = rollbar.errorHandler()

  app.renderErrorToHTML = (err, req, res, pathname, query) => {
    if (err) {
      errorHandler(err, req, res, () => {})
    }

    return _renderErrorToHTML(err, req, res, pathname, query)
  }

  return app
}
// ¯\_(ツ)_/¯

Alle 74 Kommentare

Für die Protokollierung von Fehlern auf der Clientseite haben wir Folgendes getan:
https://gist.github.com/jgautheron/044b88307d934d486f59ae87c5a5a5a0

Es sendet grundsätzlich Fehler an den Server, die am Ende an stdout ausgegeben und von unserem Docker Logging-Treiber abgefangen werden.
Wir haben SSR-Fehler mit react-guard erfolgreich abgefangen, ohne dass die Next-Kerndateien überschrieben werden mussten.

Ich habe auch dieses Problem. Ich frage mich: Würde es ausreichen, ein abgelehntes Versprechen von handleRequest von next einfach zurückzugeben? Das heißt, ändern Sie den Code hier zu:

handleRequest (req, res, parsedUrl) {
  // .....snip....

   return this.run(req, res, parsedUrl)
     .catch((err) => {
       if (!this.quiet) console.error(err)
       res.statusCode = 500
       res.end(STATUS_CODES[500])

       // rethrow error to create new, rejected promise 
       throw err;
     })
}

Dann im Benutzercode:

const app = nextJs({ dev: process.env.NODE_ENV !== 'production' });
const nextJsHandler = app.getRequestHandler();
const expressApp = express();

app.prepare().then(() => {
   // invoke express middlewares
   // ...

   // time to run next
   expressApp.use(function(req, res, next) {
     nextJsHandler(req, res).catch(e => {
       // use rejected promise to forward error to next express middleware
       next(e)
     })
   });

   // Use standard express error middlewares to handle the error from next
   // this makes it easy to log to sentry etc.
})

@arunoda @rauchg Glaubst du, die Änderung, die ich gleich oben vorgeschlagen habe, würde funktionieren? Dann sende gerne eine PR

Stimmen Sie zu, einen Fehler erneut auszulösen, damit wir damit herumspielen können.
Muss auch noch einmal auf renderToHTML werfen...

Ich bin auch in der Situation, dass wir Fehler, sowohl auf der Server- als auch auf der Client-Seite, an einen Sentry-ähnlichen Dienst senden möchten.

Ich glaube, dass die wertvollste Funktion solcher Dienste/Tools darin besteht, unerwartete Probleme zu melden, bei denen es sich meiner Erfahrung nach um nicht erkannte Fehler in der Wildnis (dh auf der Clientseite) handelt. Leider behalten die clientseitigen Handler von Next.js diese Fehler, wie bereits im verwandten Problem Nr. 2334 betont, für sich und können sie nicht an Sentry eines solchen anderen Tools weitergeben.

Was uns besonders hart getroffen hat, ist Folgendes: Eine ordnungsgemäß serverseitig gerenderte Seite wird als Fehlerseite neu gerendert, wenn vor dem React-Rendering auf der Clientseite eine nicht abgefangene Ausnahme auftritt . Dies kann entweder als großartiges Feature, aber auch als frustrierende Entwicklererfahrung angesehen werden, da es die Vorteile der Bereitstellung eines bereits gerenderten Dokuments für einen überraschend großen Teil der Clients im Wesentlichen zunichte macht.

Hier ist eine Beispielseite, die das Problem veranschaulicht:

import React from 'react';

// Works well in Node 8, but crashes in Chrome<56, Firefox<48, Edge<15, Safari<10, any IE…
const whoops = 'Phew, I made it to the client-side…'.padEnd(80);

export default () => <pre>{whoops}</pre>;

Der obige Code kann perfekt serverseitig gerendert und an den Client geliefert werden, nur um zu einem Flash Of Unwanned Content zu werden, bevor die gesamte Seite auf der Client-Seite durch die gefürchtete Meldung „Ein unerwarteter Fehler ist aufgetreten“ bei den meisten Browsern ersetzt wird , ohne eine Möglichkeit, den Fehler an Sentry (oder einen anderen Dienst/ein anderes Tool)

Dieses „Fehlerschlucken“ verhindert auch jede Nutzung des standardmäßigen onerror- Handlers, an den sich die meisten clientseitigen Fehlerberichterstellungstools anhängen (oder des moderneren, aber nicht weit verbreiteten

Mögliche clientseitige Lösung

Soweit ich das beurteilen kann, wird diese Art von clientseitigem Pre-React-Fehler im Block try / catch in client/index.js von Next.js Component , das gerendert werden soll, wird dem Wert von ErrorComponent (derzeit Zeilen 67-72 ) neu zugewiesen.

Liebe Next.js-Autoren und -Betreuer, um zu kontrollieren, was gerendert wird, was wäre Ihrer Meinung nach akzeptabel/möglich unter den folgenden Ideen:

  • einen Hook in den catch Block in client/index.js einführen, um diese Art von Fehler zu behandeln?
  • den Fehler an einen onerror/onunhandledrejection-Handler übertragen, falls einer erkannt wird?
  • eine Option zum erneuten Auslösen des Fehlers bereitstellen?
  • eine Option bereitstellen, um die Fehlerkomponente nicht anzuzeigen?
  • eine Option zum Anzeigen einer benutzerdefinierten Fehlerkomponente bereitstellen?

einen Hook in diesem catch-Block in client/index.js einführen, um diese Art von Fehler zu behandeln?
den Fehler an einen onerror/onunhandledrejection-Handler übertragen, falls einer erkannt wird?

Darüber haben wir intern gesprochen. Und wir werden uns bald ansprechen.

Ich verwende Sentry.io, um Fehler zu melden, und die Lösung, die wir anwenden, ist:

1- Konfigurieren Sie raven-node auf der Serverseite
2- Konfigurieren Sie ravenjs auf der Clientseite (wir haben das auf _document .

Mit diesen beiden Schritten fangen wir alle unbehandelten Ausnahmen sowohl auf dem Client als auch auf dem Server ab.

3- Erstellen Sie eine _error Seite. Jeder Fehler, der erzeugt wird, sobald nextjs die Anfrage bearbeitet (egal ob client- oder serverseitig), dass diese Seite gerendert wird. In der Methode getInitialProps der _error-Seite melden wir den Fehler an den Wachdienst.

Die Art und Weise zu entscheiden, wie geladen wird, wenn raven-node oder ravenjs dynamisch importiert wird, hängt davon ab, ob wir uns im Client const Raven = require('raven-js'); oder auf der Serverseite const Raven = require('raven'); .
Beachten Sie, dass wir Webpack so konfiguriert haben, dass das raven Modul (das serverseitige) nicht gebündelt wird, indem next.config.js aktualisiert wird mit:

const webpack = require('webpack');

module.exports = {
  // Do not show the X-Powered-By header in the responses
  poweredByHeader: false,
  webpack: (config) => {
    config.plugins.push(new webpack.IgnorePlugin(/^raven$/));
    return config;
  },
};

@acanimal

2- Konfigurieren Sie ravenjs auf der Clientseite (wir haben das in _document.

Können Sie mir zeigen, wie Sie raven-js auf Ihrem _document.js konfiguriert haben? Bei mir funktioniert es nicht, wenn ein Fehler auftritt, passiert nichts auf der Wache.

Muss ich alle Fehler manuell auf der Seite _error.js an den Wachdienst senden?

// _document constructor
constructor(props) {
    super(props);
    Raven
      .config('...')
      .install();
}

Next.js gibt weiterhin Fehler an console.error auf dem Server aus, solange Sie es nicht auf quiet setzen .

Mit Sentry können Sie autoBreadcrumbs aktivieren, um diese Ausgabe zu

Beispielimplementierung:

const express = require('express');
const nextjs = require('next');
const Raven = require('raven');

const dev = process.env.NODE_ENV !== 'production';

// Must configure Raven before doing anything else with it
if (!dev) {
  Raven.config('__DSN__', {
    autoBreadcrumbs: true,
    captureUnhandledRejections: true,
  }).install();
}

const app = nextjs({ dev });
const handle = app.getRequestHandler();

const captureMessage = (req, res) => () => {
  if (res.statusCode > 200) {
    Raven.captureMessage(`Next.js Server Side Error: ${res.statusCode}`, {
      req,
      res,
    });
  }
};

app
  .prepare()
  .then(() => {
    const server = express();

    if (!dev) {
      server.use((req, res, next) => {
        res.on('close', captureMessage(req, res));
        res.on('finish', captureMessage(req, res));
        next();
      });
    }

    [...]

    server.get('/', (req, res) => {
      return app.render(req, res, '/home', req.query)
    })

    server.get('*', (req, res) => {
      return handle(req, res)
    })

    server.listen('3000', (err) => {
      if (err) throw err
      console.log(`> Ready on http://localhost:${port}`)
    })
  })
  .catch(ex => {
    console.error(ex.stack);
    process.exit(1);
  });

Dies ist ein sehr konstruiertes Beispiel, das von unserem tatsächlichen Code übernommen wurde. In dieser Form habe ich es nicht getestet. Melde mich wenn es kaputt geht.

Natürlich wäre es immer noch am besten, wenn Next.js diese Fehler an Express weitergeben könnte, damit wir die Sentry/Express-Integration sofort verwenden können.

@tusgavomelo Sorry, für die späte Antwort.

Wir haben ein Update. In unserer App haben wir eine Hilfsdatei mit einer Methode, die dafür verantwortlich ist, eine Raven-Instanz zu erhalten, wobei berücksichtigt wird, ob wir uns auf der Client- oder Serverseite befinden.

let clientInstance;
let serverInstance;

const getRavenInstance = (key, config) => {
  const clientSide = typeof window !== 'undefined';

  if (clientSide) {
    if (!clientInstance) {
      const Raven = require('raven-js');  // eslint-disable-line global-require
      Raven.config(key, config).install();
      clientInstance = Raven;
    }

    return clientInstance;
  }

  if (!serverInstance) {
    // NOTE: raven (for node) is not bundled by webpack (see rules in next.config.js).
    const RavenNode = require('raven'); // eslint-disable-line global-require
    RavenNode.config(key, config).install();
    serverInstance = RavenNode;
  }
  return serverInstance;
};

Dieser Code wird sowohl auf der Serverseite (wenn eine Anfrage eintrifft) als auch auf der Clientseite ausgeführt. Was wir getan haben, ist Webpack ( next.config.js Datei) zu konfigurieren, um zu vermeiden, dass das Paket raven gebündelt wird.

@acanimal kannst du vielleicht ein funktionierendes Beispiel geben? Es scheint, dass ich nicht den vollständigen Stack-Trace bekomme? oder kannst du vielleicht dein _error.js posten?

Ich mache etwas wie RavenInstance.captureException(err) in meinem _error.js , aber ich kann nicht sehen, welche Art von Fehlern aufgetreten sind und wo?

export default class Error extends React.Component {
  static getInitialProps({ res, err }) {
    const RavenInstance = getRavenInstance('__SENTRY__')
    if (!(err instanceof Error)) {
      err = new Error(err && err.message)
    }
    RavenInstance.captureException(err)
    // const statusCode = res ? res.statusCode : err ? err.statusCode : null;

    return { }
  }

  render() {
    return (
      <div>
        <p>An error occurred on server</p>
      </div>
    )
  }
}

Dies scheint der richtige Ort zu sein, um nach benutzerdefinierter Logger-Unterstützung zu fragen, da quiet auf false , um das nächste Löschen des Bildschirms beim Neuaufbau des Moduls und damit das Löschen von Fehlern aus der Ansicht zu verhindern, aber der einzige praktikable Hack hier erfordert quiet auf false setzen.

Die Fehlerdetails sind auch im stderr-Stream verfügbar.
process.stderr.write = error => yourErrorLog(error);

Ich muss _unortodox_ Lösungen lieben

function installErrorHandler(app) {
  const _renderErrorToHTML = app.renderErrorToHTML.bind(app)
  const errorHandler = rollbar.errorHandler()

  app.renderErrorToHTML = (err, req, res, pathname, query) => {
    if (err) {
      errorHandler(err, req, res, () => {})
    }

    return _renderErrorToHTML(err, req, res, pathname, query)
  }

  return app
}
// ¯\_(ツ)_/¯

Kompakte Version, wie man den richtigen Raven für Knoten und Browser ohne benutzerdefinierte Webpack-Konfiguration erhält. Inspiriert von @acanimal Kommentar

// package.json
"browser": {
    "raven": "raven-js"
}

// getRaven.js
const Raven = require('raven')

if (process.env.NODE_ENV === 'production') {
  Raven.config('YOUR_SENTRY_DSN').install()
}

module.exports = Raven

Kern

eine kurze Zusammenfassung für alle, die dieses Problem untersuchen.

// pages/_error.js
import Raven from 'raven';
...
static async getInitialProps({ store, err, isServer }) {
   if (isServer && err) {
      // https://github.com/zeit/next.js/issues/1852
      // eslint-disable-next-line global-require
      const Raven = require('raven');

      Raven.captureException(err);
    }
    ...
// next.config.js
config.plugins.push(new webpack.IgnorePlugin(/^raven$/));

Danke an den Kommentar von @acanimal .

Installieren Sie sowohl raven (mit Webpack ignorieren, wie in den vorherigen Kommentaren vorgeschlagen) als auch raven-js , dann erstellen Sie einen Helfer zum Instanziieren des isomorphen Raven, zB lib/raven.js

import Raven from 'raven-js';

// https://gist.github.com/impressiver/5092952
const clientIgnores = {
  ignoreErrors: [
    'top.GLOBALS',
    'originalCreateNotification',
    'canvas.contentDocument',
    'MyApp_RemoveAllHighlights',
    'http://tt.epicplay.com',
    "Can't find variable: ZiteReader",
    'jigsaw is not defined',
    'ComboSearch is not defined',
    'http://loading.retry.widdit.com/',
    'atomicFindClose',
    'fb_xd_fragment',
    'bmi_SafeAddOnload',
    'EBCallBackMessageReceived',
    'conduitPage',
    'Script error.',
  ],
  ignoreUrls: [
    // Facebook flakiness
    /graph\.facebook\.com/i,
    // Facebook blocked
    /connect\.facebook\.net\/en_US\/all\.js/i,
    // Woopra flakiness
    /eatdifferent\.com\.woopra-ns\.com/i,
    /static\.woopra\.com\/js\/woopra\.js/i,
    // Chrome extensions
    /extensions\//i,
    /^chrome:\/\//i,
    // Other plugins
    /127\.0\.0\.1:4001\/isrunning/i, // Cacaoweb
    /webappstoolbarba\.texthelp\.com\//i,
    /metrics\.itunes\.apple\.com\.edgesuite\.net\//i,
  ],
};

const options = {
  autoBreadcrumbs: true,
  captureUnhandledRejections: true,
};

let IsomorphicRaven = null;

if (process.browser === true) {
  IsomorphicRaven = Raven;
  IsomorphicRaven.config(SENTRY_PUBLIC_DSN, {
    ...clientIgnores,
    ...options,
  }).install();
} else {
  // https://arunoda.me/blog/ssr-and-server-only-modules
  IsomorphicRaven = eval("require('raven')");
  IsomorphicRaven.config(
    SENTRY_DSN,
    options,
  ).install();
}

export default IsomorphicRaven;

Dann können Sie es in Ihrem pages/_error.js und es funktioniert sowohl auf der Server- als auch auf der Client-Seite.

import NextError from 'next/error';
import IsomorphicRaven from 'lib/raven';

class MyError extends NextError {
  static getInitialProps = async (context) => {
    if (context.err) {
      IsomorphicRaven.captureException(context.err);
    }
    const errorInitialProps = await NextError.getInitialProps(context);
    return errorInitialProps;
  };
}

export default MyError;

Hier ist meine PR für das Rollbar Sourcemap-Wepback-Plugin https://github.com/thredup/rollbar-sourcemap-webpack-plugin/pull/56 mit Next.js-Unterstützung :)

@tusgavomelo , Können Sie
"process.stderr.write = error => yourErrorLog(error);"

Wo sollten wir diese Codezeile schreiben, damit der Fehler in der Node-Konsole protokolliert wird?

Das ist nur Client-Seite.
Rollbar.error('some error')

https://docs.rollbar.com/docs/javascript

@teekey99 Haben Sie eine ähnliche Lösung für @sentry/browser ? Vielleicht Update mit-Sentry-Beispiel?

@sheerun Ich habe bisher raven und raven-js . Mir ist bewusst, dass diese wahrscheinlich veraltet sein werden, da alle neuen Funktionen jetzt zu @sentry/node und @sentry/browser hinzugefügt werden. Die Sache ist die, dass ich diese neuen Bibliotheken noch nicht in meinen Projekten verwendet habe, aber ich werde versuchen, sie zu untersuchen. Wenn ich ein funktionierendes Beispiel habe, komme ich darauf zurück.

Das with-sentry-Beispiel wurde kürzlich aktualisiert.

@timneutkens Ich sehe, aber es unterstützt keine serverseitigen Fehler, da Sentry in der App initialisiert wird, wo es zu spät ist, @sentry/node

@sheerun Ich habe das gleiche Problem. Die Verwendung von @sentry/node ist nicht trivial. Die Readme für dieses Sentry-Beispiel schlägt vor, einen benutzerdefinierten Server zu verwenden, den wir bereits in der Anwendung haben, an der ich arbeite. Um Ausnahmen in unserem benutzerdefinierten Express.js-Server zu erfassen, müssen Sie einen Sentry-Fehlerbehandlungs-Middleware-Fehler als erste Fehlerbehandlungs-Middleware einfügen. Wenn Sie den Fehlerhandler von Sentry direkt nach dem Next-Handler einfügen, ist der Fehler zu diesem Zeitpunkt bereits verschluckt und wird von Sentry nicht angezeigt.

Ich habe @sentry/browser im getInitialProps von _error.js und es scheint sowohl client- als auch serverseitig zu funktionieren. Ich weiß nicht, ob @sentry/browser serverseitige Unterstützung haben soll, aber ich erhalte Ereignisse an Sentry.

Obwohl ich auch Sentry.init() über @sentry/node in der Eintragsdatei eines benutzerdefinierten Express-Servers aufrufe, wird dadurch möglicherweise ein globaler Status festgelegt, den das SSR verwendet.

Hier ist ein Überblick über das Setup, das ich verwende: https://gist.github.com/mcdougal/7bf001417c3dc4b579da224b12776691

Interessant!

Hier findet definitiv eine Art globaler Zustand statt (der ein bisschen beängstigend und wahrscheinlich brüchig und unerwünscht ist). Übernehmen Ihrer Änderungen in _error.js :

  • __Ohne__ Sentry im benutzerdefinierten Server zu konfigurieren:

    • Bei Ausführung im Entwicklungsmodus oder in der Produktion (dh mit meiner erstellten App) wird Sentry nichts gemeldet, wenn ein serverseitiger Fehler auftritt, aber ich erhalte einen ReferenceError: XMLHttpRequest is not defined Fehler in den Serverprotokollen

  • __Nach der Konfiguration__ Sentry im benutzerdefinierten Server:

    • Meine serverseitigen Ausnahmen werden gemeldet, aber ich bekomme auch ein seltsames Error: Sentry syntheticException in Sentry aufgezeichnet

Es wäre gut zu verstehen, was die offizielle Lösung ist. Die Dokumentation von Next scheint zu empfehlen, jetzt eine benutzerdefinierte <App> Komponente zu verwenden, und das ist es, was das Beispiel "with Sentry" tut, aber dies funktioniert nur für die Clientseite.

Fehlerberichte werden mit Sicherheit erst auftreten, wenn die App zum ersten Mal gerendert wird. Next kann lange vorher fehlschlagen, zB beim Rendern einer Seite. Vielleicht funktioniert es in einigen Fällen zufällig, nachdem die App zum ersten Mal auf der Serverseite gerendert wurde, aber es ist mit Sicherheit keine vollständige Lösung.

Das with-sentry-Beispiel funktioniert bei mir auch nicht @timneutkens. Das Ausführen des Projekts und das Testen mit meinem tatsächlichen DSN gibt eine 400-Antwort aus und nichts gelangt zum Wachposten (Version 7 der API).

{"error":"Bad data reconstructing object (JSONDecodeError, Expecting value: line 1 column 1 (char 0))"}

Das @mcdougal hat bei mir nicht funktioniert. Es war schon nicht so toll, ein globales serverseitiges Setup zu haben, das irgendwie zum Client hochsprudelt, aber selbst mit diesem Hack würde ich Sentry 301-Antworten erhalten.

Ich sehe nicht, wie mein selbst gehostetes Sentry-Setup eine Fehlkonfiguration aufweisen könnte, da es nicht viele Optionen gibt und es in mehreren Projekten ausgeführt wird.

Ich verwende @sentry/browser auf die gleiche Weise, wie es im with-sentry-Beispiel empfohlen wird, und es scheint sowohl Fehler vom Server als auch vom Client an meinen Sentry zu senden. Ich habe keine spezielle Konfiguration, nur den gleichen Code wie im Beispiel.

@Jauny Sind Sie sicher, dass es vom Server sendet? Wie hast du das getestet? Die Readme-Datei des Beispiels scheint sogar darauf hinzudeuten, dass es auf dem Server nicht funktioniert.

@timrogers ja, in der Tat mein Fehler, ich habe angenommen, dass ein getesteter Fehler vom Server kommt, aber tatsächlich vom Client ausgelöst wurde:(

Es scheint, dass das aktuelle Beispiel with-sentry keine Fehler abfängt, die in getInitialProps geworfen werden, sondern nur im Render-Baum der Anwendung. In meinem Fall stammen die meisten Fehler von getInitialProps.

@sheerun Können Sie die obige Problemumgehung von Mcdougal ausprobieren? Es ist nicht perfekt (seltsame synthetische Wächterfehler), aber ich habe den Eindruck, dass es alle Fehler bekommt und würde gerne wissen, ob das nicht stimmt. Wenn dies zutrifft, muss das with-sentry-Beispiel wahrscheinlich damit aktualisiert werden, bis Next.js Ratschläge zur Verbesserung geben kann (idealerweise so, dass der Server.js-Sentry-Fehlerhandler nicht übersprungen wird?).

Es scheint, dass es mit zwei Hauptproblemen funktioniert:

  1. Wahrscheinlich weil asynchroner serverseitiger Code unnötig in Regenerator-Code kompiliert wird, werden serverseitige Stacktraces in der Produktion oft auf internal/process/next_tick.js abgeschnitten und es ist überhaupt keine Fehlerursache sichtbar.
  2. Die Fehlerbehandlung funktioniert nicht, wenn Fehler ausgegeben werden, bevor der nächste Request-Handler aufgerufen wird (z. B. in benutzerdefiniertem Servercode)

Tatsächlich wird nach weiterem Testen von getInitialProps von benutzerdefinierten Fehlern aus irgendeinem Grund nicht einmal in der Produktion ausgelöst, wenn ein Fehler beispielsweise in getInitialProps von benutzerdefinierten _apps auftritt.

Ja, ich habe definitiv ein seltsames Verhalten, nachdem ich ein paar Tage mit meinem Versuch gelaufen bin. Anscheinend sind die Hauptprobleme, mit denen wir konfrontiert sind:

  1. Importieren von @sentry/browser für CSR und @sentry/node für SSR
  2. Einen Ort für die Fehlerbehandlung finden, die immer sowohl für CSR als auch für SSR ausgelöst wird

Ich habe darüber nachgedacht, faule Importe und globale Zustände zu verwenden, um #1 zu lösen, so etwas wie

const sentryInitialized = false;

# Inside some trigger point
const Sentry = ssr ? eval(`require('@sentry/node')`) : eval(`require('@sentry/browser')`);
if (!sentryInitialized) {
  Sentry.init({dsn: SENTRY_DSN});
}
Sentry.captureException(err);

Vielleicht könnten die dynamischen Importe von Next verwendet werden, aber ich kenne sie noch nicht so gut. Ich bin mir auch nicht sicher, welche Auswirkungen der Aufruf von require jedes Mal hat, wenn der Fehlerbehandlungscode ausgelöst wird. Ich aktualisiere, wenn/wenn ich das versuche.

Was das Problem #2 angeht, gibt es folgende Möglichkeiten:

  1. _app.componentDidCatch , die für SSR nicht ausgelöst wird
  2. _error.getInitialProps , die eine Vielzahl von Problemen hat
  3. ...etwas anderes? Gibt es etwas, was wir für SSR in der Next-Server-Handler-Funktion tun können?

Mein Bauchgefühl ist, dass es eine Möglichkeit geben wird, dies auf dem Server zu tun, indem man den Fehlerhandler von Sentry vor dem von Next injiziert, aber ich habe es noch nicht ausprobiert.

Im Moment bietet Next keine Hooks, die Ihnen dabei helfen. Wenn wir feststellen, dass dies funktioniert, könnten wir sie hinzufügen 👌

Es besteht jedoch die Gefahr, dass dies nicht funktioniert, da Next zu früh fängt.

@mcdougal Ah &#!% Ich war so glücklich, als Ihre Wachpostens abzuhaken , die erforderlich ist, um uns in die Produktion zu bringen.

Verzeihen Sie meine völlige Unwissenheit, aber müssen wir als nächstes nur erlauben, seinen Fehlerhandler bedingt zu deaktivieren, damit der Nodejs-Sentry-Fehlerhandler der erste wird? Irgendein Flag in next.config.js namens "disableErrorHandler"?

@Enalmada Ich glaube nicht, dass Sie den Next-Fehlerhandler deaktivieren möchten, da dieser eine schöne Fehlerseite rendert. Sie möchten nur andere Middleware davor einfügen. Ich denke, das wird funktionieren, aber ich muss es versuchen.

Selbst wenn das behoben ist, habe ich immer noch nicht das Gefühl, dass die clientseitige Fehlerbehandlung so gut funktioniert, wie ich es mir erhoffe :(

Dieses ganze Problem ist eine Schande und es ist wirklich ein Blocker, um Next in der Produktion sicher auszuführen.

Zur Info ich importiere überall @sentry/node und füge folgendes in next.config.js ein:

        if (!isServer) {
          config.resolve.alias['@sentry/node$'] = '@sentry/browser'
        }

was besser sein kann als eval von @mcdougal

Hier sind meine zusätzlichen Hinweise zur benutzerdefinierten _app-Komponente und zur Fehlerbehandlung:

  1. _app.js wird für ALLE Seiten verwendet, einschließlich _error.js oder Seiten wie 404. Sie möchten also wirklich sicher sein, dass kein Fehler ausgegeben wird, wenn ctx.err an sie übergeben wird.
  2. Vergessen Sie nicht, Component.getInitialProps in getInitialProps der App aufzurufen, da dies verhindert, dass getInitialProps von _error.js aufgerufen wird (rufen Sie es auf, selbst wenn ctx.err vorhanden ist)
class MyApp extends App {
  static async getInitialProps (appContext) {
    const { Component, ctx } = appContext
    if (ctx.err) {
      if (Component.getInitialProps) {
        pageProps = await Component.getInitialProps(ctx)
      }
      return { error: true, pageProps }
    }
    // here code that can throw an error, and then:
    if (Component.getInitialProps) {
      pageProps = await Component.getInitialProps(ctx)
    }
    return { pageProps }
  }
  render() {
    if (this.props.error) return super.render()
    // rest of code that can throw an error
  }
}

Bisher finde ich das korrekte Einrichten der Fehlerberichterstattung in next.js ein sehr fragiles Verfahren :(

danke @sheerun , das sieht nach einem guten Halt in die richtige Richtung aus. Ich stimme zu, dass die Fehlerbehandlung in Next im Moment nicht optimal ist, es wird großartig sein, einige erweiterbare Module/Middleware hinzugefügt zu sehen, damit wir Fehlerbehandlung hinzufügen können usw.

Das Fehlen isomorpher Bibliotheken wie Sentry macht die Sache auch kompliziert, denn das bedeutet, dass wir keine der beiden Bibliotheken einfach in unsere Komponenten importieren können, wir müssen dies dynamisch zur Laufzeit tun, um immer zu überprüfen, ob der Fehler server- oder browserseitig ausgelöst wird.

Gibt es ein Update zu diesem Problem? Was ich bisher versucht habe, ist Folgendes: Ich habe unseren gesamten Tracking-Code in die _app.js verschoben

constructor(args: any) {
        super(args)
        Sentry.init({
            dsn: 'blah',
            environment: 'local',
        })
        Sentry.configureScope(scope => {
            scope.setTag('errorOrigin', isServer ? 'SSR' : 'Client')
        })
    }
    static async getInitialProps({ Component, router, ctx }: any) {
        let pageProps = {}

        try {
            if (Component.getInitialProps) {
                pageProps = await Component.getInitialProps(ctx)
            }
        } catch (error) {
            // console.log('we caught an error')
            console.log(error)
            Sentry.captureException(error)
            throw error
        }

        return { pageProps }
    }

gekoppelt mit dem Zusatz next.config.js von @sheerun und der Initialisierung des Wachpostens auch in server.js if (!isServer) { config.resolve.alias['@sentry/node$'] = '@sentry/browser' }
dies scheint alle Fehler auf der Clientseite zu verfolgen, aber auf der Serverseite scheint es nur den ersten Fehler zu verfolgen, der nach einem Neustart des Servers auftritt. Spätere Fehler auf dem Server werden jedoch nicht verfolgt. Bei diesem Ansatz habe ich keine SyntheticErrors im Log, sondern nur echte Fehler.

Trotzdem fühlt sich das für mich ziemlich hackig an und da das serverseitige Tracking nur beim ersten Mal funktioniert, ist es immer noch nicht nutzbar.

Ich habe auch diesen Teil aus dem with-Sentry-Beispiel hinzugefügt

    componentDidCatch(error: any, errorInfo: any) {
        // if (process.env.FIAAS_NAMESPACE !== undefined) {
        Sentry.configureScope(scope => {
            Object.keys(errorInfo).forEach(key => {
                scope.setExtra(key, errorInfo[key])
            })
        })
        Sentry.captureException(error)
        console.log('componentDidCatch')

        // This is needed to render errors correctly in development / production
        super.componentDidCatch(error, errorInfo)
        // }
    }

aber ich bin mir nicht ganz sicher ob das nötig ist

In meinem Fall mit funktioniert ohne Probleme. auch solltest du keine Wache einleiten
_app.js-Konstruktor, aber außerhalb dieser Klasse vollständig

Am Mittwoch, den 21. November 2018 um 14:53 Uhr schrieb abraxxas [email protected] :

Gibt es ein Update zu diesem Problem? Was ich bisher versucht habe ist folgendes: Ich
haben unseren gesamten Tracking-Code in die Datei _app.js verschoben

`
Konstruktor(Argumente: beliebig) {
super(argumente)
Sentry.init({
dsn: 'bla',
Umgebung: 'lokal',
})
Sentry.configureScope(scope => {
scope.setTag('errorOrigin', isServer ? 'SSR' : 'Client')
})
}

statisch asynchron getInitialProps({ Component, router, ctx }: any) {
let pageProps = {}

try {
    if (Component.getInitialProps) {
        pageProps = await Component.getInitialProps(ctx)
    }
} catch (error) {
    // console.log('we caught an error')
    console.log(error)
    Sentry.captureException(error)
    throw error
}

return { pageProps }

}

`

gekoppelt mit dem Zusatz next.config.js von @sheerun
https://github.com/sheerun und Initialisierung des Wachpostens auch in der server.js, wenn
(!isServer) { config.resolve.alias['@sentry/node$'] = '@sentry/browser' }
dies scheint alle Fehler auf der Client-Seite zu verfolgen, aber auf der Server-Seite
es scheint nur den ersten Fehler zu verfolgen, der nach einem Neustart des
Server. Spätere Fehler auf dem Server werden jedoch nicht verfolgt. Mit diesem
Ansatz Ich habe keine SyntheticErrors im Log, sondern nur echte Fehler.

Trotzdem fühlt sich das für mich ziemlich hackig an und da das serverseitige Tracking ist
funktioniert nur beim ersten mal ist immer noch unbrauchbar.


Sie erhalten dies, weil Sie erwähnt wurden.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/zeit/next.js/issues/1852#issuecomment-440668980 oder stumm
der Faden
https://github.com/notifications/unsubscribe-auth/AAR2DeIhoOj6PdWRA2VqiEZyrO5Jui8vks5uxVrHgaJpZM4NOQlp
.

Ich habe schon versucht, es herauszuziehen und immer noch das gleiche Verhalten. @sheerun könntest du vielleicht einen minimalen Kern deines Setups posten? Ich habe versucht, es mit den von Ihnen bereitgestellten Snippets einzurichten, und ich kann es einfach nicht zum Laufen bringen. Das Ganze scheint zu kompliziert für eine eher einfache Aufgabe :( Initialisierst du Sentry auch auf dem Server oder nur in _app.js außerhalb der Klasse?

Ich würde das offizielle Wachenbeispiel aktualisieren, aber ich fürchte, es wird als "zu komplex" abgelehnt. Ich kann jedoch versuchen, etwas zu posten, wenn ich Zeit finde.

@sheerun Sogar ein Versuch, auf das offizielle Beispiel zu aktualisieren, wäre von großem Wert. Ich denke, es würde zusammengeführt, wenn es wirklich die minimale Komplexität ist, die erforderlich ist, um Sentry-SSR ohne SyntheticErrors zum Laufen zu bringen oder nur den ersten Serverfehler aufzuzeichnen, der auftritt. Dann können wir von dort aus nach Wegen suchen, es besser zu machen oder auf die Kernverbesserungen von nextj oder die isomorphe Unterstützung von Wachen zu drängen.

Nun, da wir ein notwendigerweise komplexes Arbeitsbeispiel haben, was sind die nächsten Schritte, um die Situation zu verbessern:

Das einzige, was man in next.js braucht, ist die Fähigkeit, benutzerdefinierte Middleware in next.config.js und so etwas wie next.browser.js für die universelle (isomorphe) Plugin-Konfiguration hinzuzufügen (next.config.js wird unter anderem für die Webpack-Konfiguration verwendet, was bedeutet, dass andere in dieser Datei definierte Dinge nicht im Anwendungscode verwendet werden können, da dies eine zirkuläre Abhängigkeit verursachen würde).

Für next.browser.js könnte next.js eine Konfiguration wie einen Dekorator für App- oder Dokumentkomponenten definieren. Auf diese Weise konnte ich die Sentry-Integration vollständig als Plugin implementieren.

BEARBEITEN: Ich weiß nicht, ob es dafür ein Ticket gibt, aber ich denke, @timneutkens extrahiert bereits den nächsten Server in separate Pakete. Ich denke, die beste Plugin-Schnittstelle wäre so etwas wie:

module.exports = {
  server: server => {
    server.use(Sentry.Handlers.errorHandler())
  }
}

Ich habe den Vorschlag einer solchen API in #6922 implementiert

Es ermöglicht das Hinzufügen von Dekoratoren zu benutzerdefiniertem Servercode, da der Vertrag in einen geändert wird, der nicht automatisch .listen() aufruft, sodass next.js es vor der Instanziierung weiter dekorieren kann

Ich hatte große Probleme mit dem with-sentry Beispiel, also öffnete ich eine PR für ein viel einfacheres Beispiel. Es hat nicht den ganzen Schnickschnack, aber es funktioniert für mich.

https://github.com/zeit/next.js/pull/7119

Versuchen Sie dies in benutzerdefinierten _document.js :

import React from "react";
import Document, {
  Html,
  Head,
  Main,
  NextScript,
} from "next/document";
import { NodeClient } from "@sentry/node";

const { default: getConfig } = require("next/config");
const { publicRuntimeConfig: { sentryDSN } } = getConfig();

let sentry = null;
if (sentryDSN) {
  sentry = new NodeClient({ dsn: sentryDSN });
}

export default class MyDocument extends Document {
  static async getInitialProps(ctx) {
    const initialProps = await Document.getInitialProps(ctx);
    if (ctx.err && sentry) sentry.captureException(ctx.err);
    return { ...initialProps };
  }

  render() {
    return (
      <Html>
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

Und das in benutzerdefinierten _app.js :

import * as Sentry from "@sentry/browser";

const { default: getConfig } = require("next/config");
const { publicRuntimeConfig: { sentryDSN } } = getConfig();

if (sentryDSN) {
  Sentry.init({ dsn: sentryDSN });
}

Es hilft mir.

Tbh, ich bin sehr verwirrt darüber, was die richtigen Stellen zum Abfangen von Fehlern für next.js im Moment sind. Es gibt _app.tsx, _error.tsx und _document.tsx. Es gibt einige Kommentare, die sagen, dass einige Dinge in _error.tsx abgefangen werden sollten (wie: https://github.com/zeit/next.js/pull/5727/files #r235981700), aber die aktuellen Beispiele verwenden entweder _app.tsx oder _app und _document.

Ich habe jetzt beide Möglichkeiten ausprobiert und es scheint, dass einige Fehler, die während ssr auftreten, für mich nicht erkannt werden. Welche Stellen sind jetzt die richtigen, um auf Fehler zu prüfen? Am logischsten scheint es für mich, die KomponenteDidCatch von _app und die getInitialProps von _error einzuchecken, da diese im Fehlerfall bedient wird. Ich bin etwas verwirrt über den ganzen process.on Teil im _Dokument

Könnte jemand mit tieferen Kenntnissen bitte diese Frage beantworten?

@abraxxas process.on in _document.js fängt Fehler ab, die auf dem Server auftreten. Als Zusammenfassung,

  • _document.js ist _nur serverseitig_ und wird verwendet, um das anfängliche serverseitig gerenderte Dokument-Markup zu ändern.
  • _app.js ist _nur clientseitig_ und wird zum Initialisieren von Seiten verwendet.

Wenn also auf dem Server ein Fehler auftritt, sollte er über process.on einen Fehler an Sentry senden und dann wird der Client die Standard-Fehlerseite oder _error.js rendern.

Hoffentlich hilft das: https://leerob.io/blog/configuring-sentry-for-nextjs-apps/

_app.js ist nicht nur clientseitig, componentDidCatch jedoch

@timneutkens Okay, das aktualisiert, seit ich das letzte Mal nachgesehen habe. Könnten Sie genauer erklären, warum _app.js nicht nur clientseitig ist?

@timneutkens könnten Sie vielleicht erklären, wo und warum Sie Fehler finden? Es scheint so viele Meinungen zu geben.

@timneutkens Okay, das aktualisiert, seit ich das letzte Mal nachgesehen habe. Könnten Sie genauer erklären, warum _app.js nicht nur clientseitig ist?

Hallo leerob!
Ich habe gerade eine Frage zur Zusammenführungsanfrage Ihres Beispiels gepostet:
https://github.com/zeit/next.js/pull/7360#issuecomment -514318899

Um diese Frage zu ergänzen ... Ich habe auch versucht, einen Fehler in render() auf der Serverseite auszulösen (ich habe den Zustand mit raiseErrorInRender: true gestartet, also würde das erste Rendering, also serverseitig, bereits einen Fehler auslösen) und dieser Fehler wurde auch nicht von Sentry erfasst.

Haben Sie das in Ihrer Anwendung getestet und werden diese serverseitigen Fehler wirklich erfasst? Ich verwende Next 9.

Wenn dies wirklich der Fall ist und nur die clientseitigen Fehler erfasst werden, gibt es auch keinen Grund, die Datei _document.js zu überschreiben.

Danke im Voraus für jede Hilfe!

@timneutkens Okay, das aktualisiert, seit ich das letzte Mal nachgesehen habe. Könnten Sie genauer erklären, warum _app.js nicht nur clientseitig ist?

Um Ihre Frage zu beantworten, ist _app dort, wo eine App-Komponente zum Initialisieren von Seiten definiert wird. Wir würden es in Fällen überschreiben, in denen ein dauerhaftes Layout zwischen Seitenänderungen erforderlich ist (alle Seiten verwenden dieselbe _app) oder um Redux zu verwenden. Selbst das erste Rendern, das auf der Serverseite stattfindet, rendert den Inhalt von _app (es ist nicht nur die Client-Seite).

Um diese Frage zu ergänzen ... Ich habe auch versucht, einen Fehler in render() auf der Serverseite auszulösen (ich habe den Zustand mit raiseErrorInRender: true gestartet, also würde das erste Rendering, also serverseitig, bereits einen Fehler auslösen) und dieser Fehler wurde auch nicht von Sentry erfasst.

Haben Sie es auf andere Weise geschafft, dass dieser Fehler in der Wache angezeigt wird? Ich habe versucht, es in den getInitialProps von _error zu erfassen, aber das zeigt auch nichts in der Wache. Derzeit habe ich keine zuverlässige Möglichkeit gefunden, Fehler auf dem Server zu erfassen, einige von ihnen (meistens, wenn sie mit API-Fehlern verbunden sind) werden angezeigt, aber ich habe es nicht geschafft, einen einfachen Fehler von der Fehlertestseite zu erhalten, um im Wachdienst angezeigt zu werden

Um diese Frage zu ergänzen ... Ich habe auch versucht, einen Fehler in render() auf der Serverseite auszulösen (ich habe den Zustand mit raiseErrorInRender: true gestartet, also würde das erste Rendering, also serverseitig, bereits einen Fehler auslösen) und dieser Fehler wurde auch nicht von Sentry erfasst.

Haben Sie es auf andere Weise geschafft, dass dieser Fehler in der Wache angezeigt wird? Ich habe versucht, es in den getInitialProps von _error zu erfassen, aber das zeigt auch nichts in der Wache. Derzeit habe ich keine zuverlässige Möglichkeit gefunden, Fehler auf dem Server zu erfassen, einige von ihnen (meistens, wenn sie mit API-Fehlern verbunden sind) werden angezeigt, aber ich habe es nicht geschafft, einen einfachen Fehler von der Fehlertestseite zu erhalten, um im Wachdienst angezeigt zu werden

Leider nicht. Die Lösung, von der ich denke, dass ich sie implementieren werde, besteht darin, das Beispiel (ohne die überschriebene Datei _document.js) als meine Vorlage zu verwenden, um Fehler zu erfassen, die auf der Clientseite auftreten, da ich keine Kontrolle und keine Möglichkeit habe, auf diese Fehler zuzugreifen kennen, es sei denn, Benutzer melden sich dann bei mir. Auf der Serverseite denke ich, dass ich jede Protokollzeile direkt in eine Protokolldatei umleiten werde. Das ist definitiv nicht die beste Lösung, da ich alle Fehler an derselben Stelle haben wollte, aber auf diese Weise habe ich zumindest Informationen über jeden Fehler, der in der Anwendung auftreten könnte.

Was halten Sie davon? Danke!

Um diese Frage zu ergänzen ... Ich habe auch versucht, einen Fehler in render() auf der Serverseite auszulösen (ich habe den Zustand mit raiseErrorInRender: true gestartet, also würde das erste Rendering, also serverseitig, bereits einen Fehler auslösen) und dieser Fehler wurde auch nicht von Sentry erfasst.

Haben Sie es auf andere Weise geschafft, dass dieser Fehler in der Wache angezeigt wird? Ich habe versucht, es in den getInitialProps von _error zu erfassen, aber das zeigt auch nichts in der Wache. Derzeit habe ich keine zuverlässige Möglichkeit gefunden, Fehler auf dem Server zu erfassen, einige von ihnen (meistens, wenn sie mit API-Fehlern verbunden sind) werden angezeigt, aber ich habe es nicht geschafft, einen einfachen Fehler von der Fehlertestseite zu erhalten, um im Wachdienst angezeigt zu werden

Leider nicht. Die Lösung, von der ich denke, dass ich sie implementieren werde, besteht darin, das Beispiel (ohne die überschriebene Datei _document.js) als meine Vorlage zu verwenden, um Fehler zu erfassen, die auf der Clientseite auftreten, da ich keine Kontrolle und keine Möglichkeit habe, auf diese Fehler zuzugreifen kennen, es sei denn, Benutzer melden sich dann bei mir. Auf der Serverseite denke ich, dass ich jede Protokollzeile direkt in eine Protokolldatei umleiten werde. Das ist definitiv nicht die beste Lösung, da ich alle Fehler an derselben Stelle haben wollte, aber auf diese Weise habe ich zumindest Informationen über jeden Fehler, der in der Anwendung auftreten könnte.

Was halten Sie davon? Danke!

Genau das machen wir gerade, es ist etwas klobig, aber das Beste, was uns einfallen konnte. Aber da einige serverseitige Fehler bei uns in Sentry auftauchen, muss etwas mit Sentry oder next.js passieren, denke ich. Ich habe es sowohl mit dem einfachen als auch mit dem komplexeren Beispiel versucht und beide verhalten sich gleich, daher bin ich zumindest einigermaßen zuversichtlich, dass dieses Verhalten nicht mit unserem Setup zusammenhängt

Die Leute in diesem Thread könnten an https://github.com/zeit/next.js/pull/8684 und verwandten Fehlern interessiert sein. Es verfügt über 12 verschiedene Tests von nicht behandelten Ausnahmen, mit denen Sie spielen können, um zu verstehen, welche Ausnahmen Next.js für Sie verarbeitet und welche nicht.

Gibt es Neuigkeiten zu diesem Thema?

Meine Lösung ist verwenden redux speichern den Knoten Datenfehler in holen state .Dann in dem componentDidMount von _app.js etwas tun (Warnung für Benutzer oder senden Fehler erf zum Backend).
Der Code ist dort next-antd-scaffold_server-error .

========> Zustand

import {
  SERVER_ERROR,
  CLEAR_SERVER_ERROR
} from '../../constants/ActionTypes';

const initialState = {
  errorType: []
};

const serverError = (state = initialState, { type, payload }) => {
  switch (type) {
    case SERVER_ERROR: {
      const { errorType } = state;
      errorType.includes(payload) ? null : errorType.push(payload);
      return {
        ...state,
        errorType
      };
    }
    case CLEAR_SERVER_ERROR: {
      return initialState;
    }
    default:
      return state;
  }
};

export default serverError;

=======> Aktion

import {
  SERVER_ERROR
} from '../../constants/ActionTypes';

export default () => next => action => {
  if (!process.browser && action.type.includes('FAIL')) {
    next({
      type: SERVER_ERROR,
      payload: action.type 
    });
  }
  return next(action);
};

=======> _app.js

...
componentDidMount() {
    const { store: { getState, dispatch } } = this.props;
    const { errorType } = getState().serverError;
    if (errorType.length > 0) {
      Promise.all(
        errorType.map(type => message.error(`Node Error, Code:${type}`))
      );
      dispatch(clearServerError());
    }
  }
...

Ich muss _unortodox_ Lösungen lieben

function installErrorHandler(app) {
  const _renderErrorToHTML = app.renderErrorToHTML.bind(app)
  const errorHandler = rollbar.errorHandler()

  app.renderErrorToHTML = (err, req, res, pathname, query) => {
    if (err) {
      errorHandler(err, req, res, () => {})
    }

    return _renderErrorToHTML(err, req, res, pathname, query)
  }

  return app
}
// ¯\_(ツ)_/¯

Diese Methode kann nicht auf den 404-Fehler angewendet werden, da das err-Argument bei einem 404-Fehler null ist.

Ich habe dies für den Elastic APM-Knotenclient gelöst (https://www.npmjs.com/package/elastic-apm-node)

Für alle Interessierten:

In next.config.js :

webpack: (config, { isServer, webpack }) => {
      if (!isServer) {
        config.node = {
          dgram: 'empty',
          fs: 'empty',
          net: 'empty',
          tls: 'empty',
          child_process: 'empty',
        };

        // ignore apm (might use in nextjs code but dont want it in client bundles)
        config.plugins.push(
          new webpack.IgnorePlugin(/^(elastic-apm-node)$/),
        );
      }

      return config;
} 

Dann können Sie in _error.js render func captureError manuell aufrufen:

function Error({ statusCode, message, err }) {

const serverSide = typeof window === 'undefined';

  // only run this on server side as APM only works on server
  if (serverSide) {
    // my apm instance (imports elastic-apm-node and returns  captureError)
    const { captureError } = require('../src/apm'); 

    if (err) {
      captureError(err);
    } else {
      captureError(`Message: ${message}, Status Code: ${statusCode}`);
    }
  }

}

Hey alle zusammen! Wir haben gerade eine NPM-Bibliothek für eine Express-Architektur in Next.js gestartet, ohne einen Express-Server hinzuzufügen. Es könnte für Ihre Herausforderungen bei der Behandlung von Serverfehlern hilfreich sein! Schau es dir bei Interesse an. https://github.com/oslabs-beta/connext-js

Hatte jemand Erfolg beim Abfangen (und Behandeln) von Ausnahmen, die in getServerSideProps ?

Hatte jemand Erfolg beim Abfangen (und Behandeln) von Ausnahmen, die in getServerSideProps ?

Es ist unklar, man könnte meinen, ein Framework würde eine idiomatische Möglichkeit bieten, Fehler sowohl auf dem Client als auch auf dem Server zu protokollieren 🤷‍♂️

Hatte jemand Erfolg beim Abfangen (und Behandeln) von Ausnahmen, die in getServerSideProps ?

@stephankaag

ja, bei mir hat sowas funktioniert:

Erstellen Sie zuerst eine Middleware, um die Absturzberichte zu verarbeiten. Ich habe Sentry in die Klasse CrashReporter , weil das einfache Zurückgeben von Sentry nicht funktioniert (dh req.getCrashReporter = () => Sentry ).

// crash-reporter.js

const Sentry = require("@sentry/node");

class CrashReporter {
  constructor(){
    Sentry.init({ dsn: process.env.SENTRY_DSN });
  }
  captureException(ex){
    return Sentry.captureException(ex);
  }
}

function crashReporterMiddleware(req, res, next) {
  req.getCrashReporter = () => new CrashReporter();
  next();
}

module.exports = crashReporterMiddleware;

Als nächstes laden Sie natürlich die Middleware in Ihre App, bevor der Next.js-Anforderungshandler festgelegt wird:

// server.js

const crashReporterMiddleware = require("./middleware/crash-reporter")

...

app.use(crashReporterMiddleware);

...

setHandler((req, res) => {
  return handle(req, res);
});

dann wo immer Sie getServerSideProps anrufen:

// _error.js

export async function getServerSideProps({req, res, err}) {
  const statusCode = res ? res.statusCode : err ? err.statusCode : 404;
  const crashReporter = req.getCrashReporter();
  const eventId = crashReporter.captureException(err);
  req.session.eventId = eventId;
  return {
    props: { statusCode, eventId }
  }
}
War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

flybayer picture flybayer  ·  3Kommentare

renatorib picture renatorib  ·  3Kommentare

knipferrc picture knipferrc  ·  3Kommentare

jesselee34 picture jesselee34  ·  3Kommentare

sospedra picture sospedra  ·  3Kommentare