Sentry-javascript: Google Cloud Functions - Sentry ν΄λΌμ΄μ–ΈνŠΈ μ„€μ •

에 λ§Œλ“  2019λ…„ 06μ›” 18일  Β·  35μ½”λ©˜νŠΈ  Β·  좜처: getsentry/sentry-javascript

μ•ˆλ…• νŒ€, μ‚¬λž‘ Sentry, κ°μ‚¬ν•©λ‹ˆλ‹€!

μƒˆ ν”„λ‘œμ νŠΈμ— Typescriptκ°€ ν¬ν•¨λœ Google Cloud Functionsλ₯Ό μ‚¬μš©ν•˜κ³  있으며 Sentryλ₯Ό μ‚¬μš©ν•˜μ—¬ 였λ₯˜λ₯Ό μΊ‘μ²˜ν•˜κ³  μ‹ΆμŠ΅λ‹ˆλ‹€.

이 주석 μ—μ„œ Cloud FunctionsλŠ” 타사가 Node의 μ „μ—­ 였λ₯˜ ν•Έλ“€λŸ¬μ— μ—°κ²°ν•˜λŠ” 것을 ν—ˆμš©ν•˜μ§€ μ•ŠλŠ” κ²ƒμ²˜λŸΌ λ³΄μž…λ‹ˆλ‹€.

κ·Έλž˜λ„ μ •ν™•ν•œκ°€μš”? Google Cloud Functionsμ—μ„œ Sentry JS 라이브러리λ₯Ό μ‚¬μš©ν•  수 μžˆλ‚˜μš”?

κ΄€λ ¨: https://forum.sentry.io/t/google-cloud-functions-client-setup/1970

λͺ¨λ“  35 λŒ“κΈ€

헀이, κ³ λ§ˆμ›Œ! :)

κ·Έλž˜λ„ μ •ν™•ν•œκ°€μš”? Google Cloud Functionsμ—μ„œ Sentry JS 라이브러리λ₯Ό μ‚¬μš©ν•  수 μžˆλ‚˜μš”?

https://github.com/googleapis/nodejs-error-reporting#catching -and-reporting-application-wide-uncaught-errors 및 https://github.com/googleapis/nodejs-error-reporting#unhandled - κ±°λΆ€ μ§€κΈˆ κ·Έλ ‡κ²Œ ν•  수 μžˆμ§€λ§Œ 아직 직접 ν…ŒμŠ€νŠΈν•˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€.

λ©°μΉ  λ§Œμ— ν•  수 μžˆμ§€λ§Œ, μ‹œκ°„μ΄ λ˜μ‹œλ©΄ ν•œ 번 해보셔도 μ’‹μŠ΅λ‹ˆλ‹€. :)

@kamilogorek κ°μ‚¬ν•©λ‹ˆλ‹€. ν₯미둜운!

그것이 Google Cloud Functions와 μ–΄λ–»κ²Œ μƒν˜Έ μž‘μš©ν•˜λŠ”μ§€ 잘 λͺ¨λ₯΄κ² μŠ΅λ‹ˆλ‹€. λ‚˜λŠ” μ§€κΈˆ 기술 κ³„νšμ˜ ν•œκ°€μš΄λ°μ— μžˆμœΌλ―€λ‘œ 곧 ν…ŒμŠ€νŠΈν•˜μ§€ λͺ»ν•  κ²ƒμž…λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ λ§Œμ•½ / λ‚΄κ°€ ν•  λ•Œ λ‚˜λŠ” λ‹Ήμ‹ μ—κ²Œ μ•Œλ €μ€„ κ²ƒμž…λ‹ˆλ‹€. :)

μ§€κΈˆ μš°λ¦¬λŠ” λͺ¨λ“  Cloud Functionsλ₯Ό λ‹€μŒμœΌλ‘œ λž˜ν•‘ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

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

κ·ΈλŸ¬λ‚˜ Sentryμ—μ„œ μ†ŒμŠ€ μ½”λ“œλ‚˜ λ‹€λ₯Έ μ»¨ν…μŠ€νŠΈλ₯Ό λ³Ό 수 μ—†μŠ΅λ‹ˆλ‹€.

이 톡합을 μˆ˜ν–‰ν•˜λŠ” 더 쒋은 방법이 μžˆμŠ΅λ‹ˆκΉŒ?

@vpontis κ°€ 직접 ν…ŒμŠ€νŠΈν–ˆμœΌλ©° μ»¨ν…μŠ€νŠΈ 확인이 μ œλŒ€λ‘œ μž‘λ™ν•˜λŠ” 것 κ°™μŠ΅λ‹ˆλ‹€. λ‹Ήμ‹ μ˜ κΈ°λŠ₯/ꡬ성은 λ¬΄μ—‡μž…λ‹ˆκΉŒ?

image

μ•ˆλ…•ν•˜μ„Έμš” @kamilogorek λ„μ™€μ£Όμ…”μ„œ κ°μ‚¬ν•©λ‹ˆλ‹€!

Hello World둜 얻을 수 μžˆλŠ” 것을 λ³΅μ œν–ˆμœΌλ―€λ‘œ ν›Œλ₯­ν•©λ‹ˆλ‹€.

κ·ΈλŸ¬λ‚˜ μ»¨ν…μŠ€νŠΈ λ³€μˆ˜κ°€ μ—†μŠ΅λ‹ˆλ‹€. λ²”μœ„μ—μ„œ λ³€μˆ˜μ˜ 값을 λ³Ό 수 μ—†λŠ” κ²ƒμ²˜λŸΌ? μ•„λ‹ˆλ©΄ 파이썬 κΈ°λŠ₯만 μžˆμŠ΅λ‹ˆκΉŒ?

image


λ˜ν•œ λ‚΄κ°€ λ°›κ³  μžˆλŠ” 더 λ³΅μž‘ν•œ 였λ₯˜λŠ” λ°μ΄ν„°λ² μ΄μŠ€μ— μ“°κΈ°/읽기λ₯Ό ν•  λ•Œ 슀트림/μ΄λ²€νŠΈμ— 였λ₯˜κ°€ μžˆλŠ” 것 κ°™μŠ΅λ‹ˆλ‹€.

예λ₯Ό λ“€μ–΄ μ•„λž˜ μŠ€ν¬λ¦°μƒ·μ—μ„œλŠ” μ–΄λ–€ ν•¨μˆ˜μ—μ„œ ν˜ΈμΆœλ˜μ—ˆλŠ”μ§€μ‘°μ°¨ μ•Œ 수 μ—†μŠ΅λ‹ˆλ‹€.

λ‹Ήμ‹ μ˜ μΆ”μ²œμ€ λ¬΄μ—‡μž…λ‹ˆκΉŒ? μ›λž˜ ν•¨μˆ˜ 처리기의 ν˜ΈμΆœμ„ ν¬ν•¨ν•˜λŠ” 더 κΈ΄ StackTraceλ₯Ό μ–»λŠ” 방법이 μžˆμŠ΅λ‹ˆκΉŒ? μ•„λ‹ˆλ©΄ 빡가루λ₯Ό 더 μΆ”κ°€ν•΄μ•Ό ν•˜λ‚˜μš”?

image


λ˜ν•œ μ΄λŸ¬ν•œ μ†ŒμŠ€ μ½”λ“œλ₯Ό 찾을 수 μ—†μŒ 였λ₯˜λ‘œ 인해 무슨 일이 μΌμ–΄λ‚˜κ³  μžˆλŠ”μ§€ μ•„μ‹­λ‹ˆκΉŒ?

image

κ·ΈλŸ¬λ‚˜ μ»¨ν…μŠ€νŠΈ λ³€μˆ˜κ°€ μ—†μŠ΅λ‹ˆλ‹€. λ²”μœ„μ—μ„œ λ³€μˆ˜μ˜ 값을 λ³Ό 수 μ—†λŠ” κ²ƒμ²˜λŸΌ? μ•„λ‹ˆλ©΄ 파이썬 κΈ°λŠ₯만 μžˆμŠ΅λ‹ˆκΉŒ?

파이썬만의 κΈ°λŠ₯μž…λ‹ˆλ‹€. λΆˆν–‰νžˆλ„ JSλŠ” 이 κΈ°λŠ₯을 κ΅¬ν˜„ν•˜λŠ” λ©”μ»€λ‹ˆμ¦˜μ„ μ œκ³΅ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

예λ₯Ό λ“€μ–΄ μ•„λž˜ μŠ€ν¬λ¦°μƒ·μ—μ„œλŠ” μ–΄λ–€ ν•¨μˆ˜μ—μ„œ ν˜ΈμΆœλ˜μ—ˆλŠ”μ§€μ‘°μ°¨ μ•Œ 수 μ—†μŠ΅λ‹ˆλ‹€. λ‹Ήμ‹ μ˜ μΆ”μ²œμ€ λ¬΄μ—‡μž…λ‹ˆκΉŒ? μ›λž˜ ν•¨μˆ˜ 처리기의 ν˜ΈμΆœμ„ ν¬ν•¨ν•˜λŠ” 더 κΈ΄ StackTraceλ₯Ό μ–»λŠ” 방법이 μžˆμŠ΅λ‹ˆκΉŒ? μ•„λ‹ˆλ©΄ 빡가루λ₯Ό 더 μΆ”κ°€ν•΄μ•Ό ν•˜λ‚˜μš”?

μ†ŒμΌ“μ— μ˜ν•΄ νŠΈλ¦¬κ±°λ˜μ—ˆκΈ° λ•Œλ¬Έμ— 이 νŠΉμ • ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•œ 것을 μ•Œ 수 μžˆλŠ” 방법이 μ—†μŠ΅λ‹ˆλ‹€. 그리고 μ–ΈκΈ‰ν–ˆλ“―μ΄ 이λ₯Ό μΆ”μ ν•˜λŠ” κ°€μž₯ 쒋은 방법은 db 쿼리, ν”„λ‘μ‹œ 호좜 λ˜λŠ” μ™ΈλΆ€ μ„œλΉ„μŠ€ μš”μ²­μ„ μˆ˜ν–‰ν•  λ•Œ 이동 경둜λ₯Ό μ‚¬μš©ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

그리고 μ„œλ²„λ¦¬μŠ€ μΈμŠ€ν„΄μŠ€λŠ” 수λͺ…이 κΈΈκΈ° λ•Œλ¬Έμ— λ‹€μŒμ„ ν˜ΈμΆœν•  수 μžˆμŠ΅λ‹ˆλ‹€.

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

κΉ¨λ—ν•œ 슬레이트λ₯Ό μ–»μœΌλ €λ©΄.

λ˜ν•œ μ΄λŸ¬ν•œ μ†ŒμŠ€ μ½”λ“œλ₯Ό 찾을 수 μ—†μŒ 였λ₯˜λ‘œ 인해 무슨 일이 μΌμ–΄λ‚˜κ³  μžˆλŠ”μ§€ μ•„μ‹­λ‹ˆκΉŒ?

ν”„λ‘œμ νŠΈ μ„€μ •μ—μ„œ Enable JavaScript source fetching λ₯Ό λ•λ‹ˆλ‹€. https://sentry.io/settings/kamil-ogorek/projects/testing-project/
μ„œλ²„λ¦¬μŠ€ λ…Έλ“œ μ•±μ΄λ―€λ‘œ κ·Έλ ‡κ²Œ ν•  ν•„μš”κ°€ μ—†μŠ΅λ‹ˆλ‹€.

파이썬만의 κΈ°λŠ₯μž…λ‹ˆλ‹€. λΆˆν–‰νžˆλ„ JSλŠ” 이 κΈ°λŠ₯을 κ΅¬ν˜„ν•˜λŠ” λ©”μ»€λ‹ˆμ¦˜μ„ μ œκ³΅ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

μ  μž₯. λ‚˜λŠ” νŒŒμ΄μ¬μ— λŒ€ν•΄ 이것을 μ’‹μ•„ν–ˆμŠ΅λ‹ˆλ‹€!

맀우 λ„μ›€μ΄λ˜μ—ˆμŠ΅λ‹ˆλ‹€. Kamilμ—κ²Œ κ°μ‚¬λ“œλ¦½λ‹ˆλ‹€. μ΄λŸ¬ν•œ λ³€κ²½ 사항을 κ΅¬ν˜„ν•˜κ³  더 이상 질문이 μžˆλŠ” 경우 μ—¬κΈ°μ—μ„œ λ‹€μ‹œ μ—°λ½ν•˜κ² μŠ΅λ‹ˆλ‹€. 이 λ¬Έμ œκ°€ JS μ„œλ²„λ¦¬μŠ€μ—μ„œ Sentryλ₯Ό μ‚¬μš©ν•˜λŠ” λ‹€λ₯Έ μ‚¬λžŒλ“€μ—κ²Œ 도움이 될 것이라고 ν™•μ‹ ν•©λ‹ˆλ‹€.

μ—„μ²­λ‚œ! λΆ„λ₯˜λ₯Ό μœ„ν•΄ 문제λ₯Ό 닫을 κ²ƒμ΄μ§€λ§Œ μ–Έμ œλ“ μ§€ μ €μ—κ²Œ 핑을 λ³΄λ‚΄μ£Όμ‹œλ©΄ ν•„μš”ν•˜λ©΄ λ‹€μ‹œ μ—΄κ² μŠ΅λ‹ˆλ‹€! :)

@kamilogorek Google Cloud Functions에 Breadcrumbsλ₯Ό μΆ”κ°€ν–ˆλŠ”λ° λ‹€λ₯Έ ν•¨μˆ˜ ν˜ΈμΆœμ—μ„œ 이동 경둜λ₯Ό 보고 μžˆλŠ” 것 κ°™μŠ΅λ‹ˆλ‹€.

말이 돼? Google Cloud Functionsλ₯Ό μ‚¬μš©ν•˜μ—¬ ν•˜λ‚˜μ˜ HTTP μš”μ²­μ—μ„œλ§Œ 이동 경둜λ₯Ό μ œν•œν•˜λ €λ©΄ μ–΄λ–»κ²Œ ν•΄μ•Ό ν•˜λ‚˜μš”?

말이 λ˜μ§€λ§Œ ν΄λΌμš°λ“œ κΈ°λŠ₯μ—μ„œ μ‚¬μš©ν•˜λŠ” 예제 μ½”λ“œλ₯Ό 보여주싀 수 μžˆμŠ΅λ‹ˆκΉŒ? μ΄λ ‡κ²Œν•˜λ©΄ λͺ¨λ“  것을 μ΄ν•΄ν•˜κΈ°κ°€ 더 μ‰¬μšΈ κ²ƒμž…λ‹ˆλ‹€.

@kamilogorek 정말 도움이 많이 λ˜μ—ˆμŠ΅λ‹ˆλ‹€!

Docker / Node.js와 ν•¨κ»˜ Koaλ₯Ό μ‚¬μš©ν•˜λ„λ‘ μ „ν™˜ν–ˆμŠ΅λ‹ˆλ‹€. κ·Έλž˜μ„œ μš°λ¦¬λŠ” Koa 톡합을 λ‹€μŒκ³Ό 같이 μ„€μ •ν–ˆμŠ΅λ‹ˆλ‹€: https://docs.sentry.io/platforms/node/koa/

이동 경둜λ₯Ό μ œμ™Έν•˜κ³ λŠ” κ½€ 잘 μž‘λ™ν•˜κ³  있으며 ν˜„μž¬ μš”μ²­μ— μ—°κ²°λœ 이동 경둜뿐만 μ•„λ‹ˆλΌ μ„œλ²„μ˜ λͺ¨λ“  μš”μ²­μ— β€‹β€‹λŒ€ν•œ 이동 κ²½λ‘œλ„ 보고 μžˆμŠ΅λ‹ˆλ‹€.

그것을 κ³ μΉ  방법이 μžˆμŠ΅λ‹ˆκΉŒ?

그것을 κ³ μΉ  방법이 μžˆμŠ΅λ‹ˆκΉŒ?

ν•˜μ§€λ§Œ 여기에 μ½”λ“œλ₯Ό μ œκ³΅ν•˜κΈ° 전에 ν…ŒμŠ€νŠΈν•΄μ•Ό ν•©λ‹ˆλ‹€. :)
~1-2일 후에 λ‹€μ‹œ 연락 λ“œλ¦¬κ² μŠ΅λ‹ˆλ‹€.

@kamilogorek 당신은 μ ˆλŒ€ λ ˆμ „λ“œμž…λ‹ˆλ‹€ λ‚΄ 친ꡬ

@vpontis μ΄λ―€λ‘œ μ‹€μ œλ‘œ ν•΄μ•Ό ν•  일은 미듀웨어 쀑 ν•˜λ‚˜μ—μ„œ 도메인 μΈμŠ€ν„΄μŠ€λ₯Ό λ§Œλ“œλŠ” κ²ƒμž…λ‹ˆλ‹€. 일단 거기에 있으면 SDKκ°€ 이λ₯Ό κ°μ§€ν•˜κ³  μ»¨ν…μŠ€νŠΈλ₯Ό λΆ„λ¦¬ν•˜λŠ” 데 μ‚¬μš©ν•©λ‹ˆλ‹€. parseRequest 도 거기둜 이동할 수 μžˆμŠ΅λ‹ˆλ‹€. (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 λŠ” μΆ”μΆœ ν•˜λ €λŠ” μš”μ²­ 데이터λ₯Ό μ„ νƒν•˜λŠ” 데 μ‚¬μš©ν•  수 μžˆλŠ” λͺ‡ 가지 μ˜΅μ…˜μ„ ν—ˆμš©ν•©λ‹ˆλ‹€.

@kamilogorek κ°μ‚¬ν•©λ‹ˆλ‹€!

λͺ‡ 가지 생각:

  1. ctx.req 및 `ctx.res에 μ €μž₯된 도메인에 μ‹€μ œ λ…Έλ“œ req 및 res λ₯Ό 바인딩할 수 μžˆμŠ΅λ‹ˆλ‹€.

  2. req λ…Έλ“œλ₯Ό parseRequest 둜 전달할 수 μžˆμŠ΅λ‹ˆλ‹€.

  3. μˆ˜λ™μœΌλ‘œ 였λ₯˜λ₯Ό μž‘μ€ ν›„ ctx.app.emit("error", err, ctx); λ₯Ό ν˜ΈμΆœν•˜λŠ” μ΄μœ λŠ” λ¬΄μ—‡μž…λ‹ˆκΉŒ?

    // 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);

μ‘λ‹΅λ§Œ λ°˜ν™˜ν•˜κ³  쀑앙 집쀑식 였λ₯˜ μ²˜λ¦¬κΈ°μ— 였λ₯˜λ₯Ό μ „λ‹¬ν•˜μ§€ μ•ŠμœΌλ €λŠ” κ²½μš°κ°€ μ•„λ‹κΉŒμš”?

  1. μ½”μ•„μ—μ„œλŠ” next κ°€ async μž…λ‹ˆλ‹€. λ…Έλ“œ domain.run(...) 내뢀에 λ¬Έμ œκ°€ λ°œμƒν•©λ‹ˆκΉŒ?

그것이 μ˜λ―Έκ°€ μžˆλŠ”μ§€ μ•Œλ €μ£Όμ‹­μ‹œμ˜€. 이것은 이미 맀우 μœ μš©ν•©λ‹ˆλ‹€. 이번 μ£Ό ν›„λ°˜μ— ν…ŒμŠ€νŠΈν•˜κ² μŠ΅λ‹ˆλ‹€.

Ah re 3 λ‚˜λŠ” 당신이 μ˜ˆμ œμ—μ„œ 그것을 λ³΅μ‚¬ν•˜λŠ” 것을 λ³΄μ•˜μœΌλ―€λ‘œ κ·Έ 뢀뢄은 λ¬΄μ‹œν•  κ²ƒμž…λ‹ˆλ‹€ :). μ§€κΈˆ ν…ŒμŠ€νŠΈ 쀑...

음, μž‘λ™ν•˜λŠ” 데 λ¬Έμ œκ°€ μžˆμŠ΅λ‹ˆλ‹€. Koaμ—μ„œ 도메인 콜백과 async κΈ°λŠ₯이 ν˜Όν•©λ˜μ–΄ 있기 λ•Œλ¬Έμ΄λΌκ³  μƒκ°ν•©λ‹ˆλ‹€.

λ˜ν•œ 도메인이 λ…Έλ“œ 12μ—μ„œλ„ μž‘λ™ν•˜μ§€ μ•ŠλŠ” 것 κ°™μŠ΅λ‹ˆλ‹€(비동기 μŠ€νƒ 좔적 지원을 λ°›κΈ° μœ„ν•΄ 곧 μ—…κ·Έλ ˆμ΄λ“œν•  κ³„νšμž…λ‹ˆλ‹€).

μ–΄λŠ μͺ½μ΄λ“ , λ‚˜λŠ” 도메인이 μžˆλŠ” 이 μ½”λ“œκ°€ μ–΄λ–»κ²Œ μž‘λ™ν•˜λŠ”μ§€ μ΄ν•΄ν•˜μ§€ λͺ»ν•˜κΈ° λ•Œλ¬Έμ— μ•±μ˜ μ€‘μš”ν•œ 뢀뢄에 λ„£λŠ” 것을 μ£Όμ €ν•©λ‹ˆλ‹€.

ν˜„μž¬ "ν—ˆλΈŒ"λ₯Ό ctx 에 놓고 ν˜„μž¬ μš”μ²­κ³Ό μ—°κ²°λœ addBreadcrumb λ₯Ό ν˜ΈμΆœν•˜λŠ” λ‹€λ₯Έ 방법이 μžˆμŠ΅λ‹ˆκΉŒ? Sentryμ—μ„œ ν—ˆλΈŒμ™€ λ©”μ‹œμ§€ μ²˜λ¦¬κ°€ μ–΄λ–»κ²Œ μž‘λ™ν•˜λŠ”μ§€ 잘 λͺ¨λ₯΄κ² μŠ΅λ‹ˆλ‹€...

이 μ½”λ“œλŠ” μž‘λ™ν•˜μ§€λ§Œ(이것은 두 개의 연속적인 미듀웨어 κΈ°λŠ₯μž…λ‹ˆλ‹€) μž‘λ™ν•˜λŠ” _이유_κ°€ λ§ˆμŒμ— 듀지 μ•ŠμŠ΅λ‹ˆλ‹€...

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);
  }
};

λ‚˜λŠ” 그것을 밀이라고 λΆ€λ₯Έλ‹€. λ‚˜λŠ” λ‚΄κ°€ λ§Œμ‘±ν•˜λŠ” μž‘μ—… μ†”λ£¨μ…˜μ„ 얻지 λͺ»ν–ˆμŠ΅λ‹ˆλ‹€.

λ˜ν•œ λ‚΄ 이동 경둜의 λŒ€λΆ€λΆ„μ΄ Sentryμ—μ„œ μžλ™μœΌλ‘œ μΊ‘μ²˜λ˜λŠ” console.log λ¬Έμ—μ„œ κ°€μ Έμ˜¨ κ²ƒμž„μ„ κΉ¨λ‹¬μ•˜μŠ΅λ‹ˆλ‹€. λ”°λΌμ„œ 이 이동 κ²½λ‘œκ°€ μ˜¬λ°”λ₯Έ λ²”μœ„μ— μžˆλ„λ‘ ν•˜λŠ” 방법을 μ•Œμ•„λ‚΄μ•Ό ν•©λ‹ˆλ‹€...

μ½”λ“œλ₯Ό λ‘˜λŸ¬λ³΄λ‹ˆ 도메인이 이 문제λ₯Ό ν•΄κ²°ν•˜λŠ” κ²ƒμ²˜λŸΌ λ“€λ¦½λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ 도메인은 비동기 κΈ°λŠ₯으둜 μ‹ λ’°ν•  수 μ—†λŠ” 것 κ°™μœΌλ©° 곧 μ‚¬λΌμ§ˆ κ²ƒμž…λ‹ˆλ‹€...

ν˜„μž¬ "ν—ˆλΈŒ"λ₯Ό ctx에 놓고 ν˜„μž¬ μš”μ²­κ³Ό μ—°κ²°λœ addBreadcrumbλ₯Ό ν˜ΈμΆœν•˜λŠ” λ‹€λ₯Έ 방법이 μžˆμŠ΅λ‹ˆκΉŒ?

ν—ˆλΈŒλ₯Ό ctx 에 직접 ν• λ‹Ήν•  수 μžˆμ§€λ§Œ μžλ™μœΌλ‘œ 캑처된 이동 κ²½λ‘œμ—λŠ” μž‘λ™ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. ν—ˆλΈŒλ₯Ό λ°˜ν™˜ν•˜λŠ” 데 Sentry.getCurrentHub() κ°€ ν•„μš”ν•˜κ³  이동 κ²½λ‘œκ°€ ν• λ‹Ήλ˜μ–΄μ•Ό ν•˜κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€. 그리고 그것을 κ°μ§€ν•˜λŠ” 방법 쀑 ν•˜λ‚˜λŠ” domain.active λ₯Ό μ‚¬μš©ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

κ·ΈλŸ¬λ‚˜ 도메인은 비동기 κΈ°λŠ₯으둜 μ‹ λ’°ν•  수 μ—†λŠ” 것 κ°™μœΌλ©° 곧 μ‚¬λΌμ§ˆ κ²ƒμž…λ‹ˆλ‹€...

λΆˆν–‰νžˆλ„ 2014λ…„ 12μ›” μ΄ν›„λ‘œ 사라지고 있으며 λͺ…ν™•ν•œ ꡐ체(비동기 후크가 μžˆμ§€λ§Œ μ™„λ²½ν•˜μ§€λ„ μ•ŠμŒ)κ°€ μ—†μœΌλ©° 5λ…„ λ™μ•ˆ λ…Έλ“œμ˜ μ½”μ–΄μ—μ„œ μ œκ±°λ˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€.

μš°λ¦¬λŠ” μ§€κΈˆ zone.js λ₯Ό 가지고 놀고 μžˆμŠ΅λ‹ˆλ‹€. 맀우 도움이 될 것이기 λ•Œλ¬Έμž…λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ ν˜„μž¬λ‘œμ„œλŠ” μ—¬μ „νžˆ κ±°λŒ€ν•œ PoC이며 도메인을 κ΅μ²΄ν•˜λŠ” 데 μ‚¬μš©ν•  μ‹œκΈ°λ‚˜ μ‚¬μš© μ—¬λΆ€λ₯Ό μ•Œ 수 μ—†μŠ΅λ‹ˆλ‹€.

μ•ˆλ…•ν•˜μ„Έμš” @kamilogorek μž…λ‹ˆλ‹€ .

μ²˜λ¦¬λ˜μ§€ μ•Šμ€ 였λ₯˜λ₯Ό Sentry둜 μΊ‘μ²˜ν•˜λ €κ³  μ‹œλ„ 쀑이며 https://github.com/getsentry/sentry-javascript/issues/2122#issuecomment -503440087μ—μ„œ μ–ΈκΈ‰ν•œ λ‚΄μš©μ„ μ‹œλ„ν–ˆμŠ΅λ‹ˆλ‹€.

κ·ΈλŸ¬λ‚˜ Google은 process.on('uncaughtException') 연결을 ν—ˆμš©ν•˜μ§€ μ•ŠλŠ” 것 κ°™μŠ΅λ‹ˆλ‹€. ν•΄λ‹Ή μ ‘κ·Ό 방식을 μ‚¬μš©ν•˜μ—¬ Sentry에 였λ₯˜λ₯Ό 기둝할 수 μ—†μ—ˆμŠ΅λ‹ˆλ‹€.

μ‹œλ„ν•΄ λ³Ό 것을 ꢌμž₯ν•˜λŠ” λ‹€λ₯Έ 방법이 μžˆμŠ΅λ‹ˆκΉŒ? λͺ¨λ“  ν•¨μˆ˜ 본문을 try catch λΈ”λ‘μœΌλ‘œ λž˜ν•‘ν•˜λŠ” 것은 이상적인 방법이 μ•„λ‹Œ 것 κ°™μŠ΅λ‹ˆλ‹€.

μš°λ¦¬λŠ” wrap 방식을 μ œκ³΅ν•˜μ§€λ§Œ try/catch tbh보닀 훨씬 λ‚«λ‹€κ³  μƒκ°ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

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

// becomes

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

이 λ¬Έμ œλŠ” 더 κ°„λ‹¨ν•œ λ°©μ‹μœΌλ‘œ Firebase/Google ν΄λΌμš°λ“œ κΈ°λŠ₯을 μ§€μ›ν•˜κΈ° μœ„ν•œ κΈ°λŠ₯ μš”μ²­μœΌλ‘œ μ—΄μ–΄λ‘˜ κ°€μΉ˜κ°€ μžˆλŠ” 것 κ°™μŠ΅λ‹ˆλ‹€.

ν΄λΌμ΄μ–ΈνŠΈ μΈ‘ μ„€μ •μ˜ μš©μ΄μ„±μ— λ†€λΌμšΈ μ •λ„λ‘œ 감λͺ…을 λ°›μ•˜κ³  μ„œλ²„ μΈ‘ 섀정이 훨씬 더 λ³΅μž‘ν•˜λ‹€λŠ” 것을 κΉ¨λ‹¬μ•˜μ„ λ•Œ μ‹€λ§ν–ˆμŠ΅λ‹ˆλ‹€. GCP(νŠΉμ • κΈ°λŠ₯)에 λŒ€ν•œ κ²½ν—˜μ„ κ°œμ„ ν•  κ³„νšμ΄ μžˆμŠ΅λ‹ˆκΉŒ?

@goleary 보고 싢은 λ‚΄μš©μ„ μ •ν™•νžˆ μ„€λͺ…ν•˜λŠ” μƒˆ 호λ₯Ό μ—΄μ–΄μ£Όμ‹œκ² μŠ΅λ‹ˆκΉŒ?
이 μŠ€λ ˆλ“œλŠ” 이미 μƒλ‹Ήνžˆ μ»€μ„œ 따라가기 μ–΄λ ΅μŠ΅λ‹ˆλ‹€.

감사 ν•΄μš”

이것을 μ„€μ •ν•˜λŠ” 더 κ°„λ‹¨ν•œ 방법이 μ—¬μ „νžˆ μžˆμŠ΅λ‹ˆκΉŒ? λͺ¨λ“  κΈ°λŠ₯에 λŒ€ν•΄ μ„€μ •ν•  ν•„μš” 없이 μ „μ—­μ μœΌλ‘œ ν•œ 번 μ„€μ •ν•˜λŠ” 것이 μ΄μƒμ μž…λ‹ˆκΉŒ?

@marcospgp μ•„λ‹ˆμš”. λΆˆν–‰νžˆλ„ Google μžμ²΄μ—μ„œ 이λ₯Ό ν—ˆμš©ν•˜λŠ” λ©”μ»€λ‹ˆμ¦˜μ„ μ œκ³΅ν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ— 없을 κ²ƒμž…λ‹ˆλ‹€. 자체 기자 μ°Έμ‘° - https://cloud.google.com/error-reporting/docs/setup/nodejs μˆ˜λ™ ν˜ΈμΆœλ„ μ‚¬μš©ν•©λ‹ˆλ‹€.

흠 ν₯λ―Έλ‘­λ„€μš”. μ €λŠ” (λ°°ν›„μ—μ„œ Google ν΄λΌμš°λ“œ κΈ°λŠ₯을 μ‚¬μš©ν•˜λŠ”) Firebase ν΄λΌμš°λ“œ κΈ°λŠ₯μ—μ„œ Sentryλ₯Ό μ„€μ •ν–ˆκ³  방금 였λ₯˜ λ³΄κ³ μ„œλ₯Ό λ°›μ•˜μŠ΅λ‹ˆλ‹€. κ·Έλž˜μ„œ μž‘λ™ν•˜λŠ” 것 κ°™μŠ΅λ‹ˆλ‹€!

λ‹€μŒμ€ λͺ¨λ“  Sentry μ½”λ“œκ°€ μžˆλŠ” index.jsμž…λ‹ˆλ‹€.

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 λŠ” μœ„μ˜ index.js μ—μ„œ ./cloud-functions/function1 및 ./cloud-functions/function2 λ‚΄μ—μ„œ ν¬μ°©λ˜μ§€ μ•Šμ€ μ˜ˆμ™Έλ₯Ό Sentry둜 보낼 수 μžˆμ—ˆμŠ΅λ‹ˆκΉŒ? μ•„λ‹ˆλ©΄ ν•΄λ‹Ή 파일 λ‚΄μ—μ„œ Sentry에 적극적으둜 λ‘œκ·ΈμΈν•΄μ•Ό ν–ˆμŠ΅λ‹ˆκΉŒ?

방금 @marcospgp μ†”λ£¨μ…˜μ„ μ‹œλ„ν–ˆμ§€λ§Œ ν¬μ°©λ˜μ§€ μ•Šμ€ μ˜ˆμ™Έλ₯Ό κΈ°λ‘ν•˜μ§€ μ•ŠλŠ” 것 κ°™μŠ΅λ‹ˆλ‹€. κ·ΈλŠ” μˆ˜λ™μœΌλ‘œ μ˜ˆμ™Έλ₯Ό 기둝해야 ν•©λ‹ˆλ‹€( sentry.captureException() μ‚¬μš©).

@goleary 와 λ§ˆμ°¬κ°€μ§€λ‘œ 아무 것도 κΈ°λ‘λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

λ˜ν•œ .wrap() 은(λŠ”) 더 이상 μ‚¬μš©ν•  수 μ—†λŠ” 것 κ°™μŠ΅λ‹ˆλ‹€.

try/catch λ‚΄λΆ€μ˜ λͺ¨λ“  μ½”λ“œλ₯Ό μˆ˜λ™μœΌλ‘œ λž˜ν•‘ν•΄μ•Ό ν•œλ‹€λŠ” μ˜λ―Έμž…λ‹ˆκΉŒ?

@Dinduks 그게 λ‚΄κ°€ ν•˜λŠ” 일이야. μ˜€λ²„ν—€λ“œλŠ” μ•½κ°„ μ„±κ°€μ‹œμ§€λ§Œ μ„ΌνŠΈλ¦¬λ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€λŠ” 것은 Firebase ν΄λΌμš°λ“œ κΈ°λŠ₯ λ‘œκΉ…(λ³„λ‘œ 쒋지 μ•ŠμŒ)에 λŒ€ν•œ λ…Έλ ₯의 κ°€μΉ˜κ°€ μžˆμŠ΅λ‹ˆλ‹€.

@Dinduks wrap κ°€ μ—¬μ „νžˆ μžˆμŠ΅λ‹ˆλ‹€. https://github.com/getsentry/sentry-javascript/blob/master/packages/browser/src/exports.ts#L40 μ°Έμ‘°
κ·ΈλŸ¬λ‚˜ μ¦‰μ‹œ ν•¨μˆ˜λ₯Ό μ‹€ν–‰ν•˜κ³  λ°˜ν™˜ 값을 λ°˜ν™˜ν•œλ‹€λŠ” 점을 λͺ…μ‹¬ν•˜μ‹­μ‹œμ˜€. λ”°λΌμ„œ 일뢀 μ‚¬μš©μž 폴백 μž‘μ—…λ„ μˆ˜ν–‰ν•  수 μžˆλŠ” 일반 try/catch보닀 이것이 더 도움이 λ˜λŠ”μ§€ 잘 λͺ¨λ₯΄κ² μŠ΅λ‹ˆλ‹€.

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

λ‚˜λŠ” 그것이 쒋은 생각이라고 μƒκ°ν•˜μ§€ μ•Šμ§€λ§Œ λ‹€μŒκ³Ό 같은 래퍼λ₯Ό λ§Œλ“€μ—ˆμŠ΅λ‹ˆλ‹€.

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);
    }
  };
};

λ‹€μŒκ³Ό 같이 μ‚¬μš©λ©λ‹ˆλ‹€.

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

더 쒋은 방법이 μžˆλŠ”μ§€ μ•Œκ³  μ‹ΆμŠ΅λ‹ˆλ‹€.

@kamilogorek
저도 이거 κ³ λ―Όμ€‘μž…λ‹ˆλ‹€.

λ‚˜λŠ” μ„±κ³΅μ μœΌλ‘œ Sentry.init() ν–ˆκ³  try {} catch {} 문으둜 λͺ¨λ“  μ½”λ“œλ₯Ό λž˜ν•‘ν•˜κ³  Sentry.captureException 및 Sentry.flush() 에 λŒ€ν•œ μˆ˜λ™ ν˜ΈμΆœμ„ ν•  λ•Œ λ¬Έμ œκ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€.
κ·ΈλŸ¬λ‚˜ try/catch 문을 μ œκ±°ν•˜λ©΄ 아무 것도 λ³΄κ³ λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
ν•¨μˆ˜ μ‹œμž‘ λΆ€λΆ„μ—μ„œ Sentry.startTransaction() 둜 νŠΈλžœμž­μ…˜μ„ μˆ˜λ™μœΌλ‘œ μƒμ„±ν•˜μ§€ μ•ŠλŠ” ν•œ 아무 것도 얻지 λͺ»ν•˜λŠ” μ„±λŠ₯ λͺ¨λ‹ˆν„°λ§λ„ λ§ˆμ°¬κ°€μ§€μž…λ‹ˆλ‹€.

μ˜ˆμƒλ˜λŠ” μΌμž…λ‹ˆκΉŒ?
μ²˜λ¦¬λ˜μ§€ μ•Šμ€ 였λ₯˜λ₯Ό Sentry둜 λ³΄λ‚΄λŠ” 방법이 μžˆμŠ΅λ‹ˆκΉŒ?
그렇지 μ•Šμ€ 경우 μ„±λŠ₯ 탭이 항상 μ‹€νŒ¨μœ¨μ„ 0%둜 μ„€μ •ν•œλ‹€λŠ” μ˜λ―Έμž…λ‹ˆκΉŒ? (였λ₯˜λ₯Ό μž‘μ•„μ„œ μˆ˜λ™μœΌλ‘œ λ³΄κ³ ν•˜κΈ° λ•Œλ¬Έμ— νŠΈλžœμž­μ…˜μ΄ μ œλŒ€λ‘œ λ‹«ν˜€μ„œ ok μƒνƒœμΈκ°€μš”?)

@axelvaindal μš°λ¦¬λŠ” 아직 μ„œλ²„λ¦¬μŠ€μ— λŒ€ν•œ μ„±λŠ₯ λͺ¨λ‹ˆν„°λ§μ„ μ§€μ›ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 이 μ§ˆλ¬Έμ— λŒ€ν•΄:

μ²˜λ¦¬λ˜μ§€ μ•Šμ€ 였λ₯˜λ₯Ό Sentry둜 λ³΄λ‚΄λŠ” 방법이 μžˆμŠ΅λ‹ˆκΉŒ?

그러면 그렇지 μ•ŠμŠ΅λ‹ˆλ‹€. GCFλŠ” μ²˜λ¦¬λ˜μ§€ μ•Šμ€ μ˜ˆμ™Έ/거뢀에 μ—°κ²°ν•˜λŠ” 방법을 μ œκ³΅ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ 이λ₯Ό κ°€λ‘œμ±Œ 수 μ—†μŠ΅λ‹ˆλ‹€. ν•Έλ“€λŸ¬λ₯Ό μˆ˜λ™μœΌλ‘œ 작으렀면 ν•Έλ“€λŸ¬λ₯Ό λž˜ν•‘ν•΄μ•Ό ν•©λ‹ˆλ‹€(μœ„ 주석 μ°Έμ‘°).

AWSLambda ν•Έλ“€λŸ¬ κ΅¬ν˜„μ„ 읽고 ν•΄λ‹Ή μŠ€λ‹ˆνŽ«μ„ κ°œμ„ ν•˜λŠ” 방법에 λŒ€ν•œ 아이디어λ₯Ό 얻을 μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. https://github.com/getsentry/sentry-javascript/blob/master/packages/serverless/src/awslambda.ts

이 νŽ˜μ΄μ§€κ°€ 도움이 λ˜μ—ˆλ‚˜μš”?
0 / 5 - 0 λ“±κΈ‰