Sentry-javascript: Fungsi Google Cloud - Pengaturan Klien Sentry

Dibuat pada 18 Jun 2019  ·  35Komentar  ·  Sumber: getsentry/sentry-javascript

Hai tim, sayang Sentry, terima kasih!

Saya menggunakan Google Cloud Functions dengan TypeScript untuk proyek baru dan saya ingin menggunakan Sentry untuk menangkap kesalahan.

Dari komentar ini , sepertinya Cloud Functions tidak mengizinkan pihak ketiga terhubung ke penangan kesalahan global Node.

Apakah itu masih akurat? Bisakah saya membuat perpustakaan Sentry JS berfungsi dengan Google Cloud Functions?

Terkait: https://forum.sentry.io/t/google-cloud-functions-client-setup/1970

Semua 35 komentar

Hei, terima kasih! :)

Apakah itu masih akurat? Bisakah saya membuat perpustakaan Sentry JS berfungsi dengan Google Cloud Functions?

Menurut https://github.com/googleapis/nodejs-error-reporting#catching -and-reporting-application-wide-uncaught-errors dan https://github.com/googleapis/nodejs-error-reporting#unhandled - penolakan itu mungkin untuk melakukannya sekarang, namun, saya belum mengujinya sendiri.

Saya dapat melakukannya dalam beberapa hari, tetapi Anda dapat mencobanya jika Anda memiliki waktu luang :)

Terima kasih @kamilogorek. Menarik!

Saya tidak yakin bagaimana itu berinteraksi dengan Google Cloud Functions. Saya sedang dalam perencanaan teknis sekarang jadi tidak akan mengujinya segera. Tapi saya akan memberi tahu Anda jika / ketika saya melakukannya. :)

Saat ini kami hanya membungkus semua Fungsi Cloud kami di:

try () {
...
} catch (e) {
  Sentry.captureException(e);
}

Tetapi kami tidak melihat kode sumber atau konteks lain di Sentry.

Apakah ada cara yang lebih baik untuk melakukan integrasi ini?

@vpontis baru saja mengujinya sendiri dan resolusi konteks tampaknya berfungsi dengan baik. Apa fungsi/konfigurasi Anda?

image

Hai @kamilogorek terima kasih telah membantu!

Saya telah meniru apa yang Anda dapatkan dengan Hello World, jadi itu bagus.

Tetapi tidak ada variabel konteks. Seperti Anda tidak dapat melihat nilai variabel dalam ruang lingkup? Atau apakah itu hanya fitur Python?

image


Juga, sepertinya kesalahan yang lebih rumit yang saya dapatkan adalah ketika saya membuat penulisan/pembacaan ke database dan ada beberapa kesalahan pada aliran/acara.

Misalnya, pada tangkapan layar di bawah, saya bahkan tidak tahu dari fungsi apa itu dipanggil.

Apa rekomendasi Anda? Apakah ada cara untuk mendapatkan StackTrace yang lebih panjang yang menyertakan panggilan dari pengendali fungsi asal? Atau apakah saya hanya perlu menambahkan lebih banyak remah roti?

image


Juga, tahu apa yang terjadi dengan Kode Sumber ini tidak menemukan kesalahan?

image

Tetapi tidak ada variabel konteks. Seperti Anda tidak dapat melihat nilai variabel dalam ruang lingkup? Atau apakah itu hanya fitur Python?

Ini hanya fitur Python. Sayangnya, JS tidak menyediakan mekanisme untuk mengimplementasikan fitur ini.

Misalnya, pada tangkapan layar di bawah, saya bahkan tidak tahu dari fungsi apa itu dipanggil. Apa rekomendasi Anda? Apakah ada cara untuk mendapatkan StackTrace yang lebih panjang yang menyertakan panggilan dari pengendali fungsi asal? Atau apakah saya hanya perlu menambahkan lebih banyak remah roti?

Tidak ada cara untuk mengetahui apa yang disebut fungsi khusus ini, karena dipicu oleh soket. Dan seperti yang Anda sebutkan, cara terbaik untuk melacak ini adalah dengan menggunakan remah roti saat Anda melakukan kueri db, panggilan proxy, atau permintaan layanan eksternal.

Dan karena instans tanpa server berumur panjang, Anda dapat memanggil:

Sentry.configureScope(scope => scope.clear())
// or
Sentry.configureScope(scope => scope.clearBreadcrumbs())

untuk mendapatkan yang bersih.

Juga, tahu apa yang terjadi dengan Kode Sumber ini tidak menemukan kesalahan?

Matikan Enable JavaScript source fetching di pengaturan proyek Anda, mis. https://sentry.io/settings/kamil-ogorek/projects/testing-project/
Ini adalah aplikasi node tanpa server, jadi tidak ada gunanya melakukan itu.

Ini hanya fitur Python. Sayangnya, JS tidak menyediakan mekanisme untuk mengimplementasikan fitur ini.

Berengsek. Saya menyukai ini tentang Python!

Sangat membantu, terima kasih Kamil. Saya akan menerapkan perubahan tersebut dan menghubungi Anda kembali di sini jika saya memiliki pertanyaan lagi. Saya yakin masalah ini akan membantu orang lain yang menggunakan Sentry di JS tanpa server.

Luar biasa! Saya akan menutup masalah untuk kepentingan triase, tetapi jangan ragu untuk melakukan ping kepada saya kapan saja dan saya akan membukanya kembali jika perlu! :)

@kamilogorek Saya menambahkan remah roti di Google Cloud Functions dan saya pikir saya melihat remah roti dari panggilan fungsi yang berbeda.

Apakah itu masuk akal? Bagaimana saya bisa membatasi remah roti hanya dari satu permintaan HTTP dengan Google Cloud Functions?

Masuk akal, namun bisakah Anda menunjukkan kepada saya contoh kode yang Anda gunakan di fungsi cloud Anda? Dengan cara ini akan lebih mudah untuk memahami semuanya.

@kamilogorek Anda sangat membantu!

Kami beralih menggunakan Koa dengan Docker / Node. Jadi kami memiliki integrasi Koa yang diatur seperti ini: https://docs.sentry.io/platforms/node/koa/

Ini bekerja cukup bagus kecuali untuk remah roti, kami melihat remah roti untuk semua permintaan di server, bukan hanya remah roti yang terkait dengan permintaan saat ini.

Apakah ada cara untuk memperbaikinya?

Apakah ada cara untuk memperbaikinya?

Ada, tapi saya perlu mengujinya sebelum memberikan kode di sini :)
Saya akan mencoba menghubungi Anda kembali dalam ~1-2 hari.

@kamilogorek kamu adalah legenda mutlak temanku

@vpontis jadi satu-satunya hal yang perlu Anda lakukan adalah membuat instance domain di salah satu middlewares Anda. Setelah ada di sana, SDK akan mendeteksinya dan menggunakannya untuk memisahkan konteksnya. Anda juga dapat memindahkan parseRequest ke sana. (contoh berdasarkan https://github.com/koajs/examples/blob/master/errors/app.js )

const Sentry = require("@sentry/node");
const Koa = require("koa");
const app = (module.exports = new Koa());
const domain = require("domain");

Sentry.init({
  // ...
});

app.use(async function(ctx, next) {
  const local = domain.create();
  local.add(ctx);
  local.on("error", next);
  local.run(() => {
    Sentry.configureScope(scope => {
      scope.addEventProcessor(event => Sentry.Handlers.parseRequest(event, ctx.request));
    });
    next();
  });
});

app.use(async function(ctx, next) {
  try {
    await next();
  } catch (err) {
    // some errors will have .status
    // however this is not a guarantee
    ctx.status = err.status || 500;
    ctx.type = "html";
    ctx.body = "<p>Something <em>exploded</em>, please contact Maru.</p>";

    // since we handled this manually we'll
    // want to delegate to the regular app
    // level error handling as well so that
    // centralized still functions correctly.
    ctx.app.emit("error", err, ctx);
  }
});

// response

app.use(async function() {
  throw new Error("boom boom");
});

// error handler

app.on("error", function(err) {
  Sentry.captureException(err);
});

if (!module.parent) app.listen(3000);

parseRequest menerima beberapa opsi yang mungkin ingin Anda gunakan untuk memilih data permintaan yang ingin Anda ekstrak - https://github.com/getsentry/sentry-javascript/blob/f71c17426c7053d46fe3e2e35e77c564749d0eb7/packages/node/src/handlers .ts#L177

Terima kasih @kamilogorek!

Beberapa pemikiran:

  1. Anda dapat mengikat Node req dan res yang sebenarnya ke domain yang disimpan di ctx.req dan `ctx.res

  2. Anda dapat meneruskan Node req ke parseRequest

  3. Mengapa Anda memanggil ctx.app.emit("error", err, ctx); setelah menangkap kesalahan secara manual?

    // since we handled this manually we'll
    // want to delegate to the regular app
    // level error handling as well so that
    // centralized still functions correctly.
    ctx.app.emit("error", err, ctx);

Bukankah itu kasus di mana Anda hanya ingin mengembalikan respons dan tidak meneruskan kesalahan ke penangan kesalahan terpusat?

  1. Di Koa next adalah async . Apakah itu akan menyebabkan masalah apa pun di dalam Node domain.run(...)

Beri tahu saya jika itu masuk akal. Ini sudah menjadi super, sangat membantu. Saya akan mengujinya akhir minggu ini.

Ah re 3 Saya melihat Anda hanya menyalin itu dari contoh jadi saya akan mengabaikan bagian itu :). Mengujinya sekarang...

Hmm, saya kesulitan menjalankan ini. Saya pikir itu karena pencampuran panggilan balik domain dan fungsi async di Koa.

Juga sepertinya domain bahkan tidak berfungsi di Node 12 (Saya berencana untuk segera memutakhirkan untuk mendapatkan dukungan jejak tumpukan async).

Either way, saya tidak mengerti bagaimana kode ini dengan domain bekerja jadi saya ragu untuk meletakkannya di bagian penting dari aplikasi.

Apakah ada cara lain untuk menempatkan "hub" saat ini pada ctx dan memanggil addBreadcrumb entah bagaimana terkait dengan permintaan saat ini? Saya tidak yakin bagaimana hub dan penanganan pesan bekerja di Sentry...

Saya membuat kode ini berfungsi (ini adalah dua fungsi middleware yang berurutan) tetapi saya tidak merasa nyaman dengan _why_ ini berfungsi ...

export const setSentryDomain = async (ctx, next) => {
  await new Promise(async (resolve, reject) => {
    const local = domain.create();

    local.add(ctx.req);
    local.add(ctx.res);

    local.run(async () => {
      Sentry.configureScope((scope) => {
        scope.addEventProcessor((event) => Sentry.Handlers.parseRequest(event, ctx.req));
      });

      await next();
      resolve();
    });
  });
};

export const catchErrors = async (ctx, next) => {
  try {
    await next();
  } catch (err) {
    console.log('got error');
    ctx.app.emit('error', err, ctx);
  }
};

Aku menyebutnya malam. Saya tidak mendapatkan solusi kerja yang saya senangi.

Saya juga menyadari bahwa sebagian besar remah roti saya berasal dari pernyataan console.log yang secara otomatis ditangkap oleh Sentry. Jadi saya perlu mencari cara agar remah roti ini berada pada cakupan yang tepat...

Saya melihat-lihat kode dan domain sepertinya memecahkan masalah ini. Tetapi domain tampaknya tidak dapat diandalkan dengan fungsi async dan mereka akan segera ditiadakan...

Apakah ada cara lain untuk meletakkan "hub" saat ini di ctx dan memanggil addBreadcrumb entah bagaimana terkait dengan permintaan saat ini?

Anda dapat menetapkan hub langsung ke ctx , namun itu tidak akan berfungsi untuk remah roti yang diambil secara otomatis, karena memerlukan Sentry.getCurrentHub() untuk mengembalikan hub, remah roti harus ditetapkan. Dan salah satu cara mendeteksinya adalah dengan menggunakan domain.active .

Tetapi domain tampaknya tidak dapat diandalkan dengan fungsi async dan mereka akan segera ditiadakan...

Sayangnya, mereka akan pergi sejak Desember 2014 , tanpa penggantian yang jelas (ada pengait asinkron, tetapi mereka juga tidak sempurna) yang terlihat, serta mereka tidak dihapus dari inti simpul dalam 5 tahun itu.

Kami bermain-main dengan zone.js sekarang, karena ini akan sangat membantu, tetapi masih merupakan PoC yang besar untuk saat ini dan tidak dapat memastikan kapan atau bahkan apakah kami akan menggunakannya untuk mengganti domain.

Hai @kamilogorek ,

Saya mencoba menangkap kesalahan yang tidak tertangani ke Sentry, dan mencoba apa yang Anda sebutkan di https://github.com/getsentry/sentry-javascript/issues/2122#issuecomment -503440087

Tapi saya kira google tidak mengizinkan Anda terhubung ke process.on('uncaughtException') , saya tidak dapat mencatat kesalahan apa pun ke Sentry menggunakan pendekatan itu.

Apakah ada cara lain yang Anda sarankan untuk dicoba, membungkus setiap fungsi tubuh dalam blok try catch sepertinya bukan cara yang ideal untuk dilakukan.

Kami menyediakan metode wrap , tapi menurut saya ini tidak lebih baik daripada mencoba/menangkap tbh.

exports.helloBackground = (data, context) => {
  return `Hello ${data.name || 'World'}!`;
};

// becomes

exports.helloBackground = (data, context) => {
  return Sentry.wrap(() => {
    return `Hello ${data.name || 'World'}!`;
  })
};

Bagi saya masalah ini mungkin layak untuk tetap dibuka sebagai permintaan fitur untuk mendukung fungsi cloud firebase/google dengan cara yang lebih sederhana.

Saya sangat terkesan dengan kemudahan pengaturan di sisi klien dan kecewa ketika saya menyadari bahwa pengaturan sisi server akan jauh lebih rumit. Apakah ada rencana untuk meningkatkan pengalaman di GCP (fungsi khusus)?

@goleary Maukah Anda membuka edisi baru dengan tepat menggambarkan apa yang ingin Anda lihat?
Utas ini sudah cukup besar dan sulit diikuti.

Terima kasih

Apakah masih ada cara yang lebih sederhana untuk mengatur ini? Idealnya dapat mengaturnya sekali secara global, tanpa harus mengaturnya untuk setiap fungsi?

@marcospgp tidak, dan sayangnya, tidak akan ada, karena Google sendiri tidak menyediakan mekanisme yang memungkinkan itu. Lihat reporter mereka sendiri - https://cloud.google.com/error-reporting/docs/setup/nodejs itu menggunakan panggilan manual juga.

Hmm menarik, saya mengatur Sentry di fungsi cloud Firebase (yang menggunakan fungsi cloud google di belakang layar) dan saya baru saja mendapat laporan kesalahan - jadi sepertinya berhasil!

Inilah index.js saya, di mana semua kode Sentry adalah:

const admin = require("firebase-admin");
const functions = require("firebase-functions");
const Sentry = require("@sentry/node");

/**
 * Set up Sentry for error reporting
 */
if (functions.config().sentry && functions.config().sentry.dsn) {
  Sentry.init({ dsn: functions.config().sentry.dsn });
} else {
  console.warn(
    "/!\\ sentry.dsn environment variable not found. Skipping setting up Sentry..."
  );
}

admin.initializeApp();

const { function1 } = require("./cloud-functions/function1");
const { function2 } = require("./cloud-functions/function2");

module.exports = {
  function1,
  function2
};

@marcospgp apakah index.js di atas dapat mengirim pengecualian yang tidak tertangkap dalam ./cloud-functions/function1 dan ./cloud-functions/function2 ke Sentry, atau apakah Anda harus secara aktif masuk ke Sentry di dalam file-file itu?

Saya baru saja mencoba solusi @marcospgp , tetapi sepertinya tidak mencatat pengecualian yang tidak tertangkap, ia harus mencatatnya secara manual (menggunakan sentry.captureException() ?)

Sama seperti @goleary di sini, tidak ada yang dicatat.

Juga tampaknya .wrap() tidak tersedia lagi.

Apakah ini berarti kita harus membungkus semua kode secara manual di dalam try/catches?

@Dinduks itulah yang saya lakukan. Overhead sedikit mengganggu tetapi dapat menggunakan penjaga sepadan dengan usaha atas logging fungsi cloud firebase (tidak bagus).

@Dinduks wrap masih ada, lihat: https://github.com/getsentry/sentry-javascript/blob/master/packages/browser/src/exports.ts#L40
Namun, perlu diingat bahwa itu menjalankan fungsi dengan segera dan memberi Anda nilai pengembalian kembali. Jadi saya tidak yakin apakah itu lebih membantu daripada coba/tangkap biasa yang memungkinkan Anda melakukan beberapa tindakan mundur pengguna juga.

const myHandler = (req, res) => Sentry.wrap(() => {
  someFunctionThatCanBreak(req);
  return res.send(200);
});

Menurut saya itu bukan ide yang bagus, tetapi saya telah membuat pembungkus yang terlihat seperti ini.

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

export const sentryWrapper = (f) => {
  return async function () {
    try {
      // eslint-disable-next-line prefer-rest-params
      return await f.apply(this, arguments);
    } catch (e) {
      Sentry.captureException(e);
      await Sentry.flush(2000);
      throw new Error(e);
    }
  };
};

Ini akan digunakan sebagai berikut.

export const getChannelVideoTest = functions.https.onRequest(
  sentryWrapper(async (req, res) => {
    someFunctionThatCanBreak(req);
    return res.send(200);
  }),
);

Saya ingin tahu apakah ada cara yang lebih baik.

@kamilogorek
Saya berjuang dengan ini juga.

Saya telah berhasil Sentry.init() dan saya mendapatkan masalah ketika saya membungkus semua kode saya dalam pernyataan try {} catch {} dan panggilan manual ke Sentry.captureException dan Sentry.flush() .
Namun, saya tidak bisa mendapatkan apa pun yang dilaporkan jika saya menghapus pernyataan try/catch .
Hal yang sama berlaku untuk pemantauan kinerja di mana saya tidak mendapatkan apa pun kecuali saya secara manual membuat transaksi dengan Sentry.startTransaction() di awal fungsi.

Apakah ini diharapkan?
Apakah ada cara untuk mengirim kesalahan yang tidak tertangani ke Sentry?
Jika tidak, apakah ini berarti tab performance akan selalu menyetel tingkat kegagalan pada 0% ? (karena kami menangkap kesalahan dan melaporkannya secara manual, transaksi ditutup dengan benar, sehingga statusnya ok?)

@axelvaindal kami belum mendukung pemantauan kinerja untuk tanpa server. Adapun pertanyaan ini:

Apakah ada cara untuk mengirim kesalahan yang tidak tertangani ke Sentry?

Maka tidak, tidak juga, karena GCF tidak menyediakan cara untuk menghubungkan ke pengecualian/penolakan yang tidak tertangani, jadi kami tidak dapat mencegatnya. Anda perlu membungkus penangan Anda (lihat komentar di atas milik Anda) untuk menangkapnya secara manual.

Anda juga dapat membaca implementasi penangan AWSLambda kami untuk mendapatkan beberapa ide tentang cara meningkatkan cuplikan itu - https://github.com/getsentry/sentry-javascript/blob/master/packages/serverless/src/awslambda.ts

Apakah halaman ini membantu?
0 / 5 - 0 peringkat