Sentry-javascript: [@sentry/node] AWS Lambda 및 기타 μ„œλ²„λ¦¬μŠ€ μ†”λ£¨μ…˜ 지원

에 λ§Œλ“  2018λ…„ 07μ›” 28일  Β·  77μ½”λ©˜νŠΈ  Β·  좜처: getsentry/sentry-javascript

  • @sentry/node 버전 4.0.0-beta.11
  • 호슀트 Sentryλ₯Ό μ‚¬μš©ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

ν˜„μž¬ 행동은 λ¬΄μ—‡μž…λ‹ˆκΉŒ?

@sentry/nodeλ₯Ό μ‚¬μš©ν•˜μ—¬ AWS λžŒλ‹€ ν•¨μˆ˜μ—μ„œ μ˜ˆμ™Έλ₯Ό μΊ‘μ²˜ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

    .catch(err => {
      Sentry.captureException(err)
      context.fail()
    })

κ·ΈλŸ¬λ‚˜ context.fail() κ°€ 호좜되고 μ˜ˆμ™Έκ°€ Sentryμ—μ„œ λλ‚˜μ§€ μ•Šμ„ λ•Œ ν”„λ‘œμ„ΈμŠ€λ₯Ό μ’…λ£Œν•©λ‹ˆλ‹€.

λ‹€μŒκ³Ό 같은 ν•΄κ²° 방법을 μˆ˜ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

    .catch(err => {
      Sentry.captureException(err)
      setTimeout(() => context.fail(), 1000)
    })

μ˜ˆμƒλ˜λŠ” λ™μž‘μ€ λ¬΄μ—‡μž…λ‹ˆκΉŒ?

λ‹€μŒκ³Ό 같이 ν•  수 μžˆλ‹€λ©΄ 쒋을 κ²ƒμž…λ‹ˆλ‹€.

    .catch(err => {
      Sentry.captureException(err, () => context.fail())
    })

λ˜λŠ” μ „μ—­μ μœΌλ‘œ μ½œλ°±μ„ μ²˜λ¦¬ν•˜λŠ” 것이 μžˆμŠ΅λ‹ˆλ‹€.

κ°€μž₯ μœ μš©ν•œ λŒ“κΈ€

@LinusU μš°λ¦¬λŠ” 이 μ‹œλ‚˜λ¦¬μ˜€λ₯Ό μœ„ν•œ νŠΉμ • μ„œλ²„λ¦¬μŠ€ νŒ¨ν‚€μ§€λ₯Ό 생성할 κ°€λŠ₯성이 λ†’μŠ΅λ‹ˆλ‹€. 연말이고 μ§€κΈˆ μ‚¬λžŒλ“€μ΄ 많이 λͺ°λ¦¬κΈ° λ•Œλ¬Έμ— μ‹œκ°„μ„ μ°Ύμ•„μ•Ό ν•©λ‹ˆλ‹€. 계속 μ•Œλ €λ“œλ¦½λ‹ˆλ‹€!

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

이것은 https://blog.sentry.io/2018/06/20/how-droplr-uses-sentry-to-debug-serverless λ₯Ό μΆ”μΈ‘ν•˜λŠ” 데 도움이 될 수 μžˆμŠ΅λ‹ˆλ‹€(콜백이 μžˆλŠ” 였래된 κΉŒλ§ˆκ·€ 버전을 μ‚¬μš©ν•˜κ³  μžˆμ§€λ§Œ μ €λŠ” λŒ€λΆ€λΆ„ callbackWaitsForEmptyEventLoop ν”Œλž˜κ·Έλ₯Ό κ°€λ¦¬ν‚΅λ‹ˆλ‹€.

아직 곡식적인 방법은 μ—†μŠ΅λ‹ˆλ‹€. 아직 베타 λ²„μ „μœΌλ‘œ ν…ŒμŠ€νŠΈ μ€‘μ΄λ―€λ‘œ λ‹€μŒ μ½”λ“œλ‘œ κ°€λŠ₯ν•©λ‹ˆλ‹€.

import { init, getDefaultHub } from '@sentry/node';

init({
  dsn: 'https://my-dsn.com/1337'
});

exports.myHandler = async function(event, context) {
  // your code

  await getDefaultHub().getClient().captureException(error, getDefaultHub().getScope());
  context.fail();
}

@kamilogorek 포인터 μ£Όμ…”μ„œ κ°μ‚¬ν•©λ‹ˆλ‹€. λ‚˜λŠ” 그것을 μ‹œλ„ν•˜κ³  ν•™μŠ΅μ„ μž¬μƒν•©λ‹ˆλ‹€.

@kamilogorek λ‹Ήμ‹ μ˜ μ œμ•ˆμ΄ νš¨κ³Όκ°€ μžˆμŠ΅λ‹ˆλ‹€. μ’€ 더 곡식적인 방법을 κΈ°λŒ€ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

@vietbui
4.0.0-rc.1 μ—μ„œ μš°λ¦¬λŠ” close λΌλŠ” ν΄λΌμ΄μ–ΈνŠΈμ— ν•¨μˆ˜λ₯Ό λ„μž…ν–ˆμœΌλ©° λ‹€μŒκ³Ό 같이 ν˜ΈμΆœν•©λ‹ˆλ‹€.

import { getCurrentHub } from '@sentry/node';

getCurrentHub().getClient().close(2000).then(result => {
      if (!result) {
        console.log('We reached the timeout for emptying the request buffer, still exiting now!');
      }
      global.process.exit(1);
})

close λŠ” λͺ¨λ“  μš”μ²­μ΄ 전솑될 λ•ŒκΉŒμ§€ 기닀리며 μ‹œκ°„ 초과(이 μ˜ˆμ—μ„œλŠ” 2000ms)에 도달할 λ•ŒκΉŒμ§€ 항상 ν•΄κ²°λ©λ‹ˆλ‹€(κ²°κ³Ό = false μ‹œκ°„ μ΄ˆκ³Όμ— 도달함).
이것은 우리의 곡식 APIμž…λ‹ˆλ‹€.
이전 μ ‘κ·Ό 방식은 μ—¬μ „νžˆ β€‹β€‹μž‘λ™ν•˜μ§€λ§Œ close 방법은 λͺ¨λ“  κ²½μš°μ— μž‘λ™ν•©λ‹ˆλ‹€.

@HazAT λ°˜κ°‘μŠ΅λ‹ˆλ‹€. λͺ¨λ“  λ…Έλ ₯에 κ°μ‚¬λ“œλ¦½λ‹ˆλ‹€.

4.0.3μ—μ„œλŠ” λžŒλ‹€ ν•¨μˆ˜μ—μ„œ λ‹€μŒκ³Ό 같이 ν˜ΈμΆœν•©λ‹ˆλ‹€.

try {
  ...
} catch (err) {
  await getCurrentHub().getClient().captureException(err, getCurrentHub().getScope())
  throw err
}

getDefaultHub()λŠ” 더 이상 μ‚¬μš©ν•  수 μ—†μŠ΅λ‹ˆλ‹€.

@vietbui μ§€κΈˆμ€ getCurrentHub 라고 ν•©λ‹ˆλ‹€. APIλ₯Ό λ‹€λ₯Έ μ–Έμ–΄ SDK와 톡합해야 ν–ˆκΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€.

@kamilogorek μ„€λͺ… κ°μ‚¬ν•©λ‹ˆλ‹€. getCurrentHub μ ‘κ·Ό 방식에 λ¬Έμ œκ°€ μžˆμŠ΅λ‹ˆλ‹€. μ–΄λ–»κ²Œλ“  μ„€μ •ν•œ λ²”μœ„κ°€ Sentryμ—μ„œ λλ‚˜μ§€ μ•Šμ•˜κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€.

κ²°κ΅­ λ‚΄ λžŒλ‹€ ν•¨μˆ˜μ—μ„œ μ˜ˆμ™Έλ₯Ό μΊ‘μ²˜ν•˜κΈ° μœ„ν•΄ @HazAT κ°€ μ œμ•ˆν•œ λŒ€λ‘œ λ‹€λ₯Έ μ ‘κ·Ό 방식을 μ·¨ν–ˆμŠ΅λ‹ˆλ‹€.

try {
  ...
} catch (err) {
  Sentry.captureException(err)
  await new Promise(resolve => Sentry.getCurrentHub().getClient().close(2000).then(resolve))
  throw err
}

그리고 그것은 μ™„λ²½ν•˜κ²Œ μž‘λ™ν•©λ‹ˆλ‹€.

이것은 μ„ΌνŠΈλ¦¬κ°€ 이벀트λ₯Ό 보내도둝 λŒ€κΈ°/κ°•μ œν•˜λŠ” ꢌμž₯ λ°©λ²•μž…λ‹ˆκΉŒ?

@albinekb 예 – https://docs.sentry.io/learn/draining/?platform=browser

이 μ†”λ£¨μ…˜μ€ μ–΄λ–€ 이유둜 μž‘λ™ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. μ½œλ“œ μŠ€νƒ€νŠΈ β€‹β€‹μ‹œκ°„μ΄ μžˆμ„ λ•Œ ν”„λ‘œλ•μ…˜μ—μ„œ 처음으둜 μž‘λ™ν•˜κ³  κ·Έ μ΄ν›„μ—λŠ” μž‘λ™ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 여기에 예제 μ½”λ“œκ°€ μžˆμŠ΅λ‹ˆλ‹€

'use strict'

const Sentry =  require('@sentry/node')
Sentry.init({
  dsn: 'xxx',
  environment: process.env.STAGE
});

module.exports.createPlaylist = async (event, context, callback) => {
  context.callbackWaitsForEmptyEventLoop = false
  if(!event.body) {
    Sentry.captureException(error)
    await new Promise(resolve => Sentry.getCurrentHub().getClient().close(2000).then(resolve))
    return {
      statusCode: 500,
      headers: { 'Content-Type': 'text/plain' },
      body: 'Missing body parameters'
    }
  }
  return {
    statusCode: 200,
  }
};

@Andriy-Kulak λ˜ν•œ λ¬Έμ„œμ— λ‹€μŒκ³Ό 같이 λͺ…μ‹œλ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

After shutdown the client cannot be used any more so make sure to only do that right before you shut down the application.

λ”°λΌμ„œ μ‘μš© ν”„λ‘œκ·Έλž¨μ΄ μ–Έμ œ μ’…λ£Œλ μ§€ λͺ¨λ₯΄λŠ” λžŒλ‹€μ—μ„œ 이것을 μ–΄λ–»κ²Œ μ²˜λ¦¬ν•  수 μžˆλŠ”μ§€ λͺ¨λ₯΄κ² μŠ΅λ‹ˆλ‹€. 이전 APIμ—μ„œμ™€ 같이 μš”μ²­λ‹Ή μ„ΌνŠΈλ¦¬λ₯Ό λ°°μˆ˜ν•˜λŠ” 것이 κ°€μž₯ μ’‹μŠ΅λ‹ˆκΉŒ?

@HazAT 이것을 λ‹€μ‹œ μ—΄ 수 μžˆμŠ΅λ‹ˆκΉŒ? μ €λŠ” Lambdaμ—μ„œ 이 μž‘μ—…μ„ μˆ˜ν–‰ν•  수 μžˆλŠ” 방법을 κ°–λŠ” 것이 μ€‘μš”ν•˜λ‹€κ³  μƒκ°ν•©λ‹ˆλ‹€. LambdaλŠ” 배포 λŒ€μƒμ΄ 점점 더 λ§Žμ•„μ§€κ³  μžˆμŠ΅λ‹ˆλ‹€.

이것은 ν˜„μž¬ μ΅œμ‹  λ²„μ „μœΌλ‘œ μ—…κ·Έλ ˆμ΄λ“œν•˜λŠ” 것을 μ°¨λ‹¨ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€...

개인적으둜 였λ₯˜λ₯Ό 보고할 λ•Œ 약속/μ½œλ°±μ„ 받을 수 μžˆλŠ” 것을 μ„ ν˜Έν•©λ‹ˆλ‹€. λ‚˜μ€‘μ— μ‹€μ œλ‘œ 닫지 μ•Šκ³  λŒ€κΈ°μ—΄μ„ λΉ„μšΈ μˆ˜μžˆλŠ” 방법이 있으면 차선책이 될 κ²ƒμž…λ‹ˆλ‹€ ...

captureException μ—μ„œ μ½œλ°±μ„ μ œκ±°ν•œ μ΄μœ λŠ” λ¬΄μ—‡μž…λ‹ˆκΉŒ?

@albinekb λ‹€μŒ 쀄을 μ œκ±°ν•˜λ©΄ μ „ν˜€ μž‘λ™ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€

await new Promise(resolve => Sentry.getCurrentHub().getClient().close(2000).then(resolve))

@LinusU μ†”λ£¨μ…˜μ΄ 무엇이며 μ„ΌνŠΈλ¦¬ λ˜λŠ” 레이븐 μ†”λ£¨μ…˜μ„ μ‚¬μš©ν•˜κ³  μžˆμŠ΅λ‹ˆκΉŒ?

λ‚˜μ—κ²Œ 기본적으둜 λ‹€μŒμ€ sentry/node @4.3.0 와 ν•¨κ»˜ μž‘λ™ν•˜μ§€λ§Œ λžŒλ‹€κ°€ μ„ΌνŠΈλ¦¬κ°€ ν•„μš”ν•œ μž‘μ—…μ„ μˆ˜ν–‰ν•  λ•ŒκΉŒμ§€ 일정 μ‹œκ°„(이 경우 2초)을 μˆ˜λ™μœΌλ‘œ κΈ°λ‹€λ¦¬κ²Œ ν•΄μ•Ό ν•©λ‹ˆλ‹€. Sentryκ°€ captureException μš”μ²­μ„ μ™„λ£Œν•˜κΈ°λ₯Ό 기닀리고 있기 λ•Œλ¬Έμ— μ™œ 거기에 μžˆμ–΄μ•Ό ν•˜λŠ”μ§€ 잘 λͺ¨λ₯΄κ² μŠ΅λ‹ˆλ‹€. 이후에 λŒ€κΈ° μ‹œκ°„μ΄ μ—†μœΌλ©΄ μ„ΌνŠΈλ¦¬κ°€ 였λ₯˜λ₯Ό 보내지 μ•ŠλŠ” 것 κ°™μŠ΅λ‹ˆλ‹€.

'use strict'

const Sentry =  require('@sentry/node')
Sentry.init({
  dsn: 'xxx',
  environment: process.env.STAGE
});

module.exports.createPlaylist = async (event, context, callback) => {
  context.callbackWaitsForEmptyEventLoop = false
  if(!event.body) {
    const error = new Error('Missing body parameters in createPlaylist')
    await Sentry.captureException(error)
    await new Promise(resolve => {setTimeout(resolve, 2000)})
    return {
      statusCode: 500,
      headers: { 'Content-Type': 'text/plain' },
      body: 'Missing body parameters'
    }
  }
  return {
    statusCode: 200,
  }
};

μš°λ¦¬λŠ” λ˜ν•œ Lambdaμ—μ„œ 이것에 λŒ€ν•΄ λΆˆνƒ€κ³  μžˆμŠ΅λ‹ˆλ‹€. μš°λ¦¬λŠ” μƒˆλ‘œμš΄ libs둜 μ‹œμž‘ν–ˆκ³  Raven으둜 λŒμ•„κ°ˆ 것을 κ³ λ €ν•˜λ©΄μ„œ μ™„μ „νžˆ μƒμžμ—μ„œ λ²—μ–΄λ‚¬μŠ΅λ‹ˆλ‹€. μš°λ¦¬λŠ” μ§€κΈˆ ν—ˆλΈŒλ₯Ό λ‹«κ³  λ‹€μ‹œ μ΄ˆκΈ°ν™”ν•˜κΈ° μœ„ν•΄ ν…ŒμŠ€νŠΈλ₯Ό μž‘μ„±ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. ν—ˆλΈŒμ— 물이 남아 μžˆλŠ” 경우 μ‹€ν–‰ κ°€λŠ₯ν•œ ν•΄κ²° 방법이 될 κ²ƒμž…λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ μ—¬μ „νžˆ ν•΄ν‚€/λ‘œλ“œ μ‹œ 문제λ₯Ό μΌμœΌν‚¬ κ°€λŠ₯성이 μžˆμŠ΅λ‹ˆλ‹€.

개인적으둜 λ‚˜λŠ” 약속을 λ°˜ν™˜ν•˜λŠ” μΌμ’…μ˜ flush() λ₯Ό μ„ ν˜Έν•©λ‹ˆλ‹€. 단점을 μ°ΎκΈ°κ°€ μ–΄λ ΅μŠ΅λ‹ˆλ‹€. 그런 일이 일어날 거라고 생각해?

μ†”λ£¨μ…˜μ€ 무엇이며 μ„ΌνŠΈλ¦¬ λ˜λŠ” 레이븐 μ†”λ£¨μ…˜μ„ μ‚¬μš©ν•˜κ³  μžˆμŠ΅λ‹ˆκΉŒ?

λ‹€μŒ μ΅μŠ€ν”„λ ˆμŠ€ 였λ₯˜ 처리기λ₯Ό μ‚¬μš©ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

app.use((err: any, req: express.Request, res: express.Response, next: express.NextFunction) => {
  let status = (err.status || err.statusCode || 500) as number

  if (process.env.NODE_ENV === 'test') {
    return next(err)
  }

  if (status < 400 || status >= 500) {
    Raven.captureException(err, () => next(err))
  } else {
    next(err)
  }
})

그런 λ‹€μŒ μŠ€μΉΈλ””μ›€ 을 μ‚¬μš©ν•˜μ—¬ Express 앱을 Lambda에 λ°°ν¬ν•©λ‹ˆλ‹€.

νŽΈμ§‘: 이것은 Raven "raven": "^2.6.3", μž…λ‹ˆλ‹€.

λ“œλ¦Ό APIλŠ” 이렇겠죠 😍

Sentry.captureException(err: Error): Promise<void>

@LinusU https://github.com/getsentry/sentry-javascript/blob/master/packages/core/src/baseclient.ts#L145 -L152 πŸ™‚

κ·ΈλŸ¬λ‚˜ 그것을 μ–»μœΌλ €λ©΄ ν΄λΌμ΄μ–ΈνŠΈ μΈμŠ€ν„΄μŠ€λ₯Ό 직접 μ‚¬μš©ν•΄μ•Όν•©λ‹ˆλ‹€. κ·Έ μ΄μœ λŠ” μ£Όμš” μ‹œλ‚˜λ¦¬μ˜€κ°€ "λ°œμ‚¬ ν›„ μžŠμ–΄λ²„λ¦¬λŠ”" μœ ν˜•μ˜ λ™μž‘μ΄λ―€λ‘œ 비동기 방식이 μ•„λ‹ˆλΌκ³  κ²°μ •ν–ˆκΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ λ‚΄λΆ€μ μœΌλ‘œλŠ” 자체적으둜 μ‚¬μš©ν•˜λŠ” 비동기 APIκ°€ μžˆμŠ΅λ‹ˆλ‹€.

λ‚΄κ°€ μ‹€μ œλ‘œ μ›ν•˜λŠ” 것은 λ‹€μŒκ³Ό 같은 것 κ°™μŠ΅λ‹ˆλ‹€.

const backend = client.getBackend()
const event = await backend.eventFromException(error)
await client.processEvent(event, finalEvent => backend.sendEvent(finalEvent))

λͺ¨λ“  νμž‰κ³Ό 버퍼링을 κ±΄λ„ˆλ›°λ €λ©΄...

λ‚˜λŠ” λ””μžμΈμ΄ "fire and forgot"에 맞좰져 있고 μž₯κΈ° μ‹€ν–‰ μ„œλ²„μ—μ„œ μ‹€ν–‰λœλ‹€λŠ” 것을 μ•Œμ•˜μŠ΅λ‹ˆλ‹€. 버퍼링 등을 많이 ν•˜κΈ° λ•Œλ¬Έμ— μ•„λ§ˆλ„ κ½€ 쒋을 κ²ƒμž…λ‹ˆλ‹€. λ¬Έμ œλŠ” 이것이 μ •λ°˜λŒ€λΌλŠ” κ²ƒμž…λ‹ˆλ‹€. 점점 더 λ³΄νŽΈν™”λ˜κ³  μžˆλŠ” Lambda, App Engine 및 기타 "μ„œλ²„λ¦¬μŠ€" μ•„ν‚€ν…μ²˜μ— λŒ€ν•΄ μ›ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

κ°€λŠ₯ν•œ ν•œ 빨리 이벀트λ₯Ό 보내고 await ν•  수 μžˆλŠ” Promise λ₯Ό λ°˜ν™˜ν•˜λŠ” νŠΉλ³„ν•œ λ©”μ„œλ“œλ₯Ό κ°€μ§ˆ 수 μžˆμŠ΅λ‹ˆκΉŒ? μ„œλ²„λ¦¬μŠ€ μ‹œλ‚˜λ¦¬μ˜€μ— μ ν•©ν•©λ‹ˆλ‹€!

class Sentry {
  // ...

  async unbufferedCaptureException(err: Error): Promise<void> {
    const backend = this.client.getBackend()
    const event = await backend.eventFromException(error)
    await this.client.processEvent(event, finalEvent => backend.sendEvent(finalEvent))
  }

  // ...
}

@LinusU μš°λ¦¬λŠ” 이 μ‹œλ‚˜λ¦¬μ˜€λ₯Ό μœ„ν•œ νŠΉμ • μ„œλ²„λ¦¬μŠ€ νŒ¨ν‚€μ§€λ₯Ό 생성할 κ°€λŠ₯성이 λ†’μŠ΅λ‹ˆλ‹€. 연말이고 μ§€κΈˆ μ‚¬λžŒλ“€μ΄ 많이 λͺ°λ¦¬κΈ° λ•Œλ¬Έμ— μ‹œκ°„μ„ μ°Ύμ•„μ•Ό ν•©λ‹ˆλ‹€. 계속 μ•Œλ €λ“œλ¦½λ‹ˆλ‹€!

이 μ‹œλ‚˜λ¦¬μ˜€μ— λŒ€ν•œ νŠΉμ • μ„œλ²„λ¦¬μŠ€ νŒ¨ν‚€μ§€λ₯Ό λ§Œλ“€ κ°€λŠ₯성이 ν½λ‹ˆλ‹€.

그것은 λ†€λΌμš΄ κ²ƒμž…λ‹ˆλ‹€! 😍

@mtford90

이 더 λ‚˜μ€ μ†”λ£¨μ…˜μ„ μ •ν™•νžˆ μ–Έμ œ μ‚¬μš©ν•©λ‹ˆκΉŒ? λ‚΄κ°€ μ•„λŠ” ν•œ λžŒλ‹€κ°€ μ–Έμ œ μ’…λ£Œλ μ§€ μ•Œ 수 μ—†μŠ΅λ‹ˆλ‹€. κ²Œλ‹€κ°€ μ„ΌνŠΈλ¦¬κ°€ μž‘λ™ν•  수 μžˆλ„λ‘ μž„μ˜μ˜ μ‹œκ°„ λ™μ•ˆ μ’…λ£Œλ₯Ό κΈ°λ‹€λ¦¬λŠ” 것은 어리석은 μΌμž…λ‹ˆλ‹€. 특히 κ³ κ°€μ˜ 높은 λ©”λͺ¨λ¦¬/CPU λžŒλ‹€ κΈ°λŠ₯μ—μ„œ κ·Έλ ‡μŠ΅λ‹ˆλ‹€.

(λ°°μΆœμ— λŒ€ν•΄ 이야기)

μ„œλ²„ ν”„λ‘œμ„ΈμŠ€λ₯Ό μ’…λ£Œν•˜κΈ° 전에 λ§ˆμ§€λ§‰μœΌλ‘œ μ‚¬μš©ν•˜κΈ° μœ„ν•œ κ²ƒμž…λ‹ˆλ‹€. drain λ©”μ„œλ“œμ˜ μ‹œκ°„ μ΄ˆκ³ΌλŠ” ν”„λ‘œμ„ΈμŠ€λ₯Ό μ’…λ£Œν•˜κΈ° 전에 λŒ€κΈ°ν•  μ΅œλŒ€ μ‹œκ°„μ΄λ©°, 이것이 항상 ν•΄λ‹Ή μ‹œκ°„μ„ μ‚¬μš©ν•œλ‹€λŠ” μ˜λ―ΈλŠ” μ•„λ‹™λ‹ˆλ‹€. μ„œλ²„κ°€ μ™„μ „νžˆ μ‘λ‹΅ν•˜λ©΄ λ‚˜λ¨Έμ§€ λͺ¨λ“  이벀트λ₯Ό μ¦‰μ‹œ λ³΄λƒ…λ‹ˆλ‹€.

이것을 κ·Έ 자체둜 μ•Œ 수 μžˆλŠ” 방법은 μ—†μ§€λ§Œ ν•Έλ“€λŸ¬μ˜ 콜백 인수λ₯Ό μ‚¬μš©ν•˜μ—¬ μ–Έμ œ μ’…λ£Œλ˜μ–΄μ•Ό ν•˜λŠ”μ§€ λžŒλ‹€μ— μ•Œλ¦¬λŠ” 방법은 μžˆμŠ΅λ‹ˆλ‹€.

λ˜ν•œ @LinusU , κ·€ν•˜μ˜ 이전 의견, 특히 이 뢀뢄을 λ‹€μ‹œ μ½μ—ˆμŠ΅λ‹ˆλ‹€.

κ°€λŠ₯ν•œ ν•œ 빨리 이벀트λ₯Ό 보내고 μš°λ¦¬κ°€ 기닀릴 수 μžˆλŠ” Promiseλ₯Ό λ°˜ν™˜ν•˜λŠ” νŠΉλ³„ν•œ λ©”μ„œλ“œλ₯Ό κ°€μ§ˆ 수 μžˆμŠ΅λ‹ˆκΉŒ? μ„œλ²„λ¦¬μŠ€ μ‹œλ‚˜λ¦¬μ˜€μ— μ ν•©ν•©λ‹ˆλ‹€!

이것이 μš°λ¦¬κ°€ 버퍼λ₯Ό κ΅¬ν˜„ν•œ λ°©λ²•μž…λ‹ˆλ‹€. ν΄λΌμ΄μ–ΈνŠΈμ— λŒ€ν•œ λͺ¨λ“  captureX ν˜ΈμΆœμ€ 버퍼에 μΆ”κ°€ν•©λ‹ˆλ‹€. λ§žμŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ μ–΄λ–€ μ‹μœΌλ‘œλ“  큐에 넣지 μ•Šκ³  μ¦‰μ‹œ μ‹€ν–‰λ˜λ©° 이 νŒ¨ν„΄μ€ λͺ¨λ“  것이 Sentry둜 μ„±κ³΅μ μœΌλ‘œ μ „μ†‘λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

https://github.com/getsentry/sentry-javascript/blob/0f0dc37a4276aa2b832da451307bc4cd5413b34d/packages/core/src/requestbuffer.ts#L12 -L18

즉, AWS Lambdaμ—μ„œ 이와 같은 μž‘μ—…μ„ μˆ˜ν–‰ν•˜λŠ” 경우(κ°€μž₯ κ°„λ‹¨ν•œ 경우인 κΈ°λ³Έ ν΄λΌμ΄μ–ΈνŠΈλ₯Ό μ‚¬μš©ν•œλ‹€κ³  κ°€μ •):

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

Sentry.init({ dsn: '__YOUR_DSN__' });

exports.handler = (event, context, callback) => {
    try {
      // do something
    catch (err) {
      Sentry.getCurrentHub()
        .getClient()
        .captureException(err)
        .then((status) => {
          // request status
          callback(null, 'Hello from Lambda');
        })
    }
};

μ¦‰μ‹œ μ „μ†‘λ˜μ—ˆμœΌλ©° 타이밍/ν”„λ‘œμ„Έμ‹± μ˜€λ²„ν—€λ“œκ°€ μ—†μŒμ„ 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.

@kamilogorek
이것은 이와 같은 것이 비동기/λŒ€κΈ° 처리기(μ½œλ°±μ„ μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” κ³³)μ—μ„œ μž‘λ™ν•΄μ•Ό 함을 μ˜λ―Έν•©λ‹ˆκΉŒ?

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

Sentry.init({ dsn: '__YOUR_DSN__' });

exports.handler = async (event, context) => {
    try {
      // do something

      return 'Hello from Lambda';
    catch (err) {
      await Sentry.getCurrentHub().getClient().captureException(err);
      return 'Hello from Lambda with error';
    }
};

@jviolas μ™„μ „νžˆ! :)

λ‹€μŒ λ³€κ²½ 사항이 μ €μ—κ²Œ 효과적일 것 κ°™μŠ΅λ‹ˆλ‹€ ☺️

-import Raven = require('raven')
+import * as Sentry from '@sentry/node'

 // ...

-Raven.config(config.SENTRY_DSN)
+Sentry.init({ dsn: config.SENTRY_DSN })

 // ...

 app.use((err: any, req: express.Request, res: express.Response, next: express.NextFunction) => {
   let status = (err.status || err.statusCode || 500) as number

   if (process.env.NODE_ENV === 'test') {
     return next(err)
   }

   if (status < 400 || status >= 500) {
-    Raven.captureException(err, () => next(err))
+    Sentry.getCurrentHub().getClient().captureException(err).then(() => next(err))
   } else {
     next(err)
   }
 })

μ†”μ§νžˆ λŒ€μ‚¬ ν•˜λ‚˜ν•˜λ‚˜κ°€ μ’€ λͺ»μƒκ²Όμ–΄μš”πŸ˜† 근데 속은 더 λ‚˜μ€κ±° κ°™μ•„μš”...

@kamilogorek μ›Ήμ‚¬μ΄νŠΈμ˜ λ¬Έμ„œμ—μ„œ getCurrentHub() λ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€. 이 APIκ°€ 큰 좩돌 없이 μ€‘λ‹¨λ˜μ§€ μ•ŠλŠ”λ‹€κ³  보μž₯λ˜λ‚˜μš”? ❀️

@kamilogorek μ›Ή μ‚¬μ΄νŠΈμ˜ λ¬Έμ„œμ—μ„œ getCurrentHub()λ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€. 이 APIλŠ” 큰 좩돌 없이 μ€‘λ‹¨λ˜μ§€ μ•ŠλŠ”λ‹€κ³  보μž₯λ©λ‹ˆκΉŒ? ❀️

예, 보μž₯λ©λ‹ˆλ‹€. 여기에 μ„€λͺ…λœ @sentry/hub νŒ¨ν‚€μ§€μ˜ μΌλΆ€μž…λ‹ˆλ‹€ - https://docs.sentry.io/enriching-error-data/scopes/?platform=browser

μš°λ¦¬λŠ” 이 μŠ€λ ˆλ“œμ—μ„œ μΌμ’…μ˜ "κ³ κΈ‰ μ‚¬μš©"에 λŒ€ν•΄ λ…Όμ˜ν•˜κ³  있으며 아직 λ¬Έμ„œν™”ν•  단계에 이λ₯΄μ§€ λͺ»ν–ˆμŠ΅λ‹ˆλ‹€. μš°λ¦¬λŠ” κ²°κ΅­ 이것을 ν•  κ²ƒμž…λ‹ˆλ‹€ :)

μ—¬κΈ°μ„œ μš°λ¦¬κ°€ λ†“μΉ˜κ³  μžˆλŠ” 것은 μ΄λŸ¬ν•œ μ’…λ₯˜μ˜ κ³ κΈ‰ μ‚¬μš© 사둀에 λŒ€ν•œ λͺ‡ 가지 λ¬Έμ„œμ™€ λͺ¨λ²” μ‚¬λ‘€μž…λ‹ˆλ‹€. λ¬Έμ„œν™”λ˜κ±°λ‚˜ λΈ”λ‘œκ·Έ κ²Œμ‹œλ¬Όλ„ 쒋은 μ‹œμž‘μ΄ 될 수 μžˆμ„ λ•Œ 정말 μ’‹μŠ΅λ‹ˆλ‹€.
그렇지 μ•ŠμœΌλ©΄ μƒˆ SDKλŠ” μ‚¬μš©ν•˜κΈ°κ°€ 정말 κ°„νŽΈν•˜κ³  톡합이 정말 μ’‹μŠ΅λ‹ˆλ‹€.

@kamilogorek
이것은 이와 같은 것이 비동기/λŒ€κΈ° 처리기(μ½œλ°±μ„ μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” κ³³)μ—μ„œ μž‘λ™ν•΄μ•Ό 함을 μ˜λ―Έν•©λ‹ˆκΉŒ?

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

Sentry.init({ dsn: '__YOUR_DSN__' });

exports.handler = async (event, context) => {
    try {
      // do something

      return 'Hello from Lambda';
    catch (err) {
      await Sentry.getCurrentHub().getClient().captureException(err);
      return 'Hello from Lambda with error';
    }
};

μΆ”κ°€ μ»¨ν…μŠ€νŠΈλ₯Ό μΆ”κ°€ν•  수 μ—†λ‹€λŠ” 점을 μ œμ™Έν•˜κ³  μœ„μ—μ„œ μ œμ•ˆν•œ λŒ€λ‘œ μž‘μ—…μ„ μˆ˜ν–‰ν•˜λ©΄ λ©λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄ λ‹€μŒκ³Ό 같이 ν•˜λ©΄

Sentry.configureScope(scope => {
   scope.setExtra('someExtraInformation', information);
});
await Sentry.getCurrentHub().getClient().captureException(err);

Sentryμ—μ„œ μ‹€μ œλ‘œ 'someExtraInformation'을 λ³Ό 수 μ—†μŠ΅λ‹ˆλ‹€.

λˆ„κ΅°κ°€κ°€ 이 μŠ€λ ˆλ“œμ˜ 맨 μœ„μ— λ‹€λ₯Έ 방법을 μ œμ•ˆν–ˆλŠ”λ° μž‘λ™ν•˜μ§€λ§Œ ν•΄ν‚Ήλœ κ²ƒμ²˜λŸΌ λ³΄μž…λ‹ˆλ‹€(μ‹œκ°„ 초과 κ°•μ œ 적용).

Sentry.configureScope(scope => {
  scope.setExtra('someExtraInformation', information);
});
Sentry.captureException(error);
await new Promise(resolve => Sentry.getCurrentHub().getClient().close(2000).then(resolve));

@kamilogorek @jviolas

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

Sentry.init({ dsn: '__YOUR_DSN__' });

exports.handler = async (event, context) => {
   try {
     // do something

     return 'Hello from Lambda';
   catch (err) {
     await Sentry.getCurrentHub().getClient().captureException(err);
     return 'Hello from Lambda with error';
   }
};

이것은 _μž‘νžˆμ§€ μ•Šμ€ μ˜ˆμ™Έ_에도 적용될 수 μžˆμŠ΅λ‹ˆκΉŒ? Sentry.Integrations.OnUncaughtException 톡합을 μˆ˜μ •ν•˜λŠ” 것이 곡식적인 방법인 것 κ°™μ§€λ§Œ λ¬Έμ„œλŠ” ν˜„μž¬ 맀우 μ—΄μ•…ν•©λ‹ˆλ‹€.

이것에 λŒ€ν•΄ +1. 적어도 κ³΅μ‹μ μœΌλ‘œ λ¬Έμ„œν™” 된 것이 있으면 쒋을 κ²ƒμž…λ‹ˆλ‹€. ServerlessλŠ” 2019λ…„ ν˜„μž¬ λΉ λ₯΄κ²Œ μ„±μž₯ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. Sentry의 곡식 지원을 정말 보고 μ‹ΆμŠ΅λ‹ˆλ‹€. μ—¬κΈ°μ—μ„œ 읽고 정말 λ§ˆμŒμ— λ“€μ—ˆλ˜ 아이디어 쀑 ν•˜λ‚˜λŠ” Sentry.flush() 와 같은 것을 μ‚¬μš©ν•˜μ—¬ λŒ€κΈ° 쀑인 λͺ¨λ“  이벀트λ₯Ό λ³΄λ‚΄λŠ” κ²ƒμ΄μ—ˆμŠ΅λ‹ˆλ‹€.

@rdsedmundo 이 μ ‘κ·Ό 방식이 νš¨κ³Όκ°€ μ—†λŠ” 이유λ₯Ό μžμ„Ένžˆ μ„€λͺ…ν•΄ μ£Όμ‹œκ² μŠ΅λ‹ˆκΉŒ?

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

Sentry.getCurrentHub().getClient().close(2000).then(result => {
      if (!result) {
        console.log('We reached the timeout for emptying the request buffer, still exiting now!');
      }
      global.process.exit(1);
})

이것은 우리의 곡식적인 μ ‘κ·Ό 방식이며 기본적으둜 Sentry.flush() μž…λ‹ˆλ‹€.
μ°Έμ‘°: https://docs.sentry.io/error-reporting/configuration/draining/?platform=javascript

@HazAT AWS Lambda μ»¨ν…Œμ΄λ„ˆ μž¬μ‚¬μš©μ— λŒ€ν•΄ 생각할 λ•Œ λ¬Έμ œκ°€ λ°œμƒν•©λ‹ˆλ‹€. μ΄λŠ” TL;DR μš©μ–΄λ‘œ μš”μ²­μ„ μ²˜λ¦¬ν•œ ν”„λ‘œμ„ΈμŠ€κ°€ 짧은 μ‹œκ°„ 내에 이루어지면 μƒˆλ‘œμš΄ λΈŒλžœλ“œλ₯Ό μ œκ³΅ν•  수 μžˆμŒμ„ μ˜λ―Έν•©λ‹ˆλ‹€. 당신이 μ œκ³΅ν•œ 이 μŠ€λ‹ˆνŽ«κ³Όμ˜ 연결을 λ‹«κ³  μ»¨ν…Œμ΄λ„ˆκ°€ μž¬μ‚¬μš©λœλ‹€λ©΄, μƒˆ μš”μ²­μ„ μœ„ν•œ μƒˆ ν—ˆλΈŒλ₯Ό μƒμ„±ν•˜λ„λ‘ 관리해야 ν•  κ²ƒμž…λ‹ˆλ‹€. λ‚˜λŠ” 이것이 κΉŒλ‹€λ‘œμ›Œμ§€λŠ” 것을 μ‰½κ²Œ λ³Ό 수 μžˆλ‹€. 이것이 κ°„λ‹¨ν•œ await Sentry.flush() κ°€ 더 λ‚˜μ€ μ†”λ£¨μ…˜μΈ μ΄μœ μž…λ‹ˆλ‹€.

import Sentry from './sentry'; // this calls Sentry.init under the hood

export const handler = async (event, context) => {
  try {
    ...
  } catch (error) {
    Sentry.captureException(error);
    await Sentry.flush(); // could even be called on the finally block

    return formatError(error);
  }
}

@rdsedmundo μ œκ°€ λ­”κ°€λ₯Ό 잘λͺ» μ΄ν•΄ν•˜κ³  μžˆλŠ”μ§€ 잘 λͺ¨λ₯΄κ² μ§€λ§Œ κ·Έλ ‡κ²Œ ν•˜μ‹œλ©΄

import Sentry from './sentry'; // this calls Sentry.init under the hood

export const handler = async (event, context) => {
  try {
    ...
  } catch (error) {
    Sentry.captureException(error);
    await Sentry.getCurrentHub().getClient().close(2000);

    return formatError(error);
  }
}

μ‹œκ°„ μ œν•œμ„ μ •μ˜ν•˜λŠ” 것은 await Sentry.flush 와 μ •ν™•νžˆ κ°™μŠ΅λ‹ˆλ‹€.

2000ms 후에 λŒ€κΈ°μ—΄μ— μ—¬μ „νžˆ 물건이 있으면 false 둜 약속이 ν•΄κ²°λ©λ‹ˆλ‹€.
그렇지 μ•ŠμœΌλ©΄ close λŠ” μ‹œκ°„ μ΄ˆκ³Όμ— λ„λ‹¬ν•˜κΈ° 전에 λŒ€κΈ°μ—΄μ΄ λΉ„μ›Œμ§€λ©΄ true 둜 ν•΄κ²°λ©λ‹ˆλ‹€.

μ•„λ‹ˆλ©΄ λͺ¨λ“  약속이 ν•΄κ²°λ˜κΈ° 전에 μ»¨ν…Œμ΄λ„ˆκ°€ μž¬μ‚¬μš©λ©λ‹ˆκΉŒ? (그건 상상도 λͺ»ν•¨)

@HazAT λŠ” close(...) 이 ν΄λΌμ΄μ–ΈνŠΈλ₯Ό λ‹€μ‹œ μ‚¬μš©ν•˜μ§€ λͺ»ν•˜κ²Œ ν•˜λŠ” λ¬Έμ œκ°€ μ•„λ‹Œκ°€μš”? LambdaλŠ” λ™μΌν•œ Node ν”„λ‘œμ„ΈμŠ€λ₯Ό μž¬μ‚¬μš©ν•˜λ―€λ‘œ close 에 λŒ€ν•œ 첫 번째 호좜 후에 μž‘λ™μ΄ 쀑지될 것 κ°™μŠ΅λ‹ˆλ‹€.

  • Sentry.init()
  • Sentry.captureException()
  • Sentry.getCurrentHub().getClient().close()
  • Sentry.captureException()
  • Sentry.getCurrentHub().getClient().close()
  • Sentry.captureException()
  • Sentry.getCurrentHub().getClient().close()
  • Sentry.captureException()
  • Sentry.getCurrentHub().getClient().close()
  • ...

μ•„λ‹ˆμš”, close λŠ” ν΄λΌμ΄μ–ΈνŠΈλ₯Ό μ‚­μ œν•˜μ§€ μ•ŠμœΌλ©° 전솑 λŒ€κΈ°μ—΄μ„ λΉ„μš°κΈ° μœ„ν•œ κ²ƒμž…λ‹ˆλ‹€.
이 μ»¨ν…μŠ€νŠΈμ—μ„œ close λΌλŠ” 이름이 μ˜€ν•΄μ˜ μ†Œμ§€κ°€ μžˆμ§€λ§Œ 적어도 JS/Nodeμ—μ„œλŠ” close λΌλŠ” 이름이 ν΄λΌμ΄μ–ΈνŠΈμ™€ 아무 관계가 μ—†μœΌλ©° λ‚˜μ€‘μ— 계속 μ‚¬μš©ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

νŽΈμ§‘: 그것이 μ‹€μ œλ‘œ "문제"μ˜€λ‹€λ©΄ 이λ₯Ό λͺ…ν™•νžˆ ν•˜κΈ° μœ„ν•΄ λ¬Έμ„œλ₯Ό μ—…λ°μ΄νŠΈν•˜κ² μŠ΅λ‹ˆλ‹€.

μ‹œμ›ν•œ. κ·ΈλŸ¬λ‚˜ λ¬Έμ„œκ°€ 잘λͺ»λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

After shutdown the client cannot be used any more so make sure to only do that right before you shut down the application.

μ’‹μŠ΅λ‹ˆλ‹€. μš°λ¦¬λŠ” 이 문제λ₯Ό νŒ€ λ‚΄λΆ€μ—μ„œ λ…Όμ˜ν–ˆμŠ΅λ‹ˆλ‹€.
μ—¬λŸ¬λΆ„μ΄ μ˜³μ•˜κ³  μ§€κΈˆ JavaScriptλŠ” μš°λ¦¬κ°€ λ¬Έμ„œν™”ν•œ λ°©μ‹μœΌλ‘œ μž‘λ™ν•˜μ§€ μ•Šμ§€λ§Œ πŸ™ˆ μ—¬λŸ¬λΆ„μ΄ κΈ°λŒ€ν•˜λŠ” 것과 μ •ν™•νžˆ μΌμΉ˜ν•˜λŠ” flush ν•¨μˆ˜λ₯Ό μ†Œκ°œν•  κ²ƒμž…λ‹ˆλ‹€.

λ”°λΌμ„œ μ§€κΈˆ λ‹Ήμž₯은 아무 문제 없이 close λ₯Ό μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€(ν–₯ν›„ ν΄λΌμ΄μ–ΈνŠΈλ₯Ό μ‚­μ œ/λΉ„ν™œμ„±ν™”ν•˜κΈ° μœ„ν•΄ λ³€κ²½ν•  것인지 ν™•μ‹€ν•˜μ§€ μ•ŠμŒ).
ν•˜μ§€λ§Œ flush ν•¨μˆ˜λŠ” _just_ flush λŒ€κΈ°μ—΄μ— μžˆμŠ΅λ‹ˆλ‹€.

κΈ°λŠ₯이 μΆœμ‹œλ˜λ©΄ 이 문제λ₯Ό μ—…λ°μ΄νŠΈν•˜κ² μŠ΅λ‹ˆλ‹€.

이 λͺ¨λ“  μ£Όμ„μ—μ„œ μ•½κ°„ μžƒμ–΄λ²„λ ΈκΈ° λ•Œλ¬Έμ— Express 였λ₯˜ 처리기(이 λ¦¬ν¬μ§€ν† λ¦¬μ˜ 였λ₯˜ 처리기 λͺ¨λ°©)λŠ” λ‹€μŒκ³Ό 같이 ν‘œμ‹œλ˜μ–΄μ•Ό ν•©λ‹ˆκΉŒ?

function getStatusCodeFromResponse(error) {
    const statusCode = error.status || error.statusCode || error.status_code || (error.output && error.output.statusCode);
    return statusCode ? parseInt(statusCode, 10) : 500;
}

app.use(async (err, req, res, next) => {
    const status = getStatusCodeFromResponse(err);

    if (status >= 500) {
        Sentry.captureException(err)

        await Sentry.getCurrentHub().getClient().close(2000)
    }

    next(err)
})

그것은 μž‘λ™ν•˜λŠ” κ²ƒμ²˜λŸΌ 보이며 @rreynier 의 μ½”λ“œμ—μ„œμ™€ 같이 μΆ”κ°€ 데이터λ₯Ό μžƒμ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

개인적으둜 κ·Έλ ‡κ²Œ λŠλ‚€λ‹€.

await Sentry.getCurrentHub().getClient().captureException(err)

λ‹€μŒλ³΄λ‹€ κΉ¨λ—ν•©λ‹ˆλ‹€.

Sentry.captureException(err)
await Sentry.getCurrentHub().getClient().close(2000)

close 정말 ν΄λΌμ΄μ–ΈνŠΈλ₯Ό 닫을 κ²ƒμ²˜λŸΌ μ½μŠ΅λ‹ˆλ‹€...

전체 예:

import * as Sentry from '@sentry/node'

// ...

Sentry.init({ dsn: config.SENTRY_DSN })

// ...

app.use((err: any, req: express.Request, res: express.Response, next: express.NextFunction) => {
  let status = (err.status || err.statusCode || 500) as number

  if (process.env.NODE_ENV === 'test') {
    return next(err)
  }

  if (status < 400 || status >= 500) {
    Sentry.getCurrentHub().getClient().captureException(err).then(() => next(err))
  } else {
    next(err)
  }
})

@LinusU μ‹œλ„ν–ˆλŠ”λ° μ–΄λ–€ 이유둜 μŠ€νƒ 좔적과 ν•¨κ»˜ μΆ”κ°€ 데이터λ₯Ό 보내지 μ•ŠμŠ΅λ‹ˆλ‹€. 기본적으둜 μŠ€νƒ μΆ”μ λ§Œ λ³΄λƒ…λ‹ˆλ‹€. μ‚¬μš©μž, OS 등에 λŒ€ν•œ 정보가 μ—†μŠ΅λ‹ˆλ‹€.

μ•„, μ „ν˜€ 쒋지 μ•Šμ•„ 😞

flush λ₯Ό κΈ°λ‹€λ¦¬λŠ” λ™μ•ˆ μœ„μ˜ 두 μ˜΅μ…˜λ³΄λ‹€ 더 μ•ˆμ •μ μΈ ν•΄κ²° λ°©λ²•μœΌλ‘œ λ³΄κ³ ν•˜κ³  κ²°κ³Όλ₯Ό 기닀릴 수 μžˆμŠ΅λ‹ˆλ‹€. μ•„λž˜ μŠ€λ‹ˆνŽ«μ„ μ‚¬μš©ν•˜μ—¬ λ²”μœ„λ₯Ό _및_ ν¬ν•¨ν•©λ‹ˆλ‹€.

const scope = Sentry.getCurrentHub().getScope();
await Sentry.getCurrentHub().getClient().captureException(error, scope);

λ‚˜λŠ” 이것을 μ‚¬μš©ν•˜κ³  있으며 λ‚΄κ°€ κΈ°λŒ€ν•˜λŠ” λͺ¨λ“  것을 ν¬ν•¨ν•˜μ—¬ 보고된 였λ₯˜μ™€ ν•¨κ»˜ μ•ˆμ •μ μœΌλ‘œ μž‘λ™ν•˜λŠ” 것 κ°™μŠ΅λ‹ˆλ‹€.

μ €λŠ” μ‹€μ œλ‘œ 이 λͺ¨λ“  것을 Netlify Functions와 ν•¨κ»˜ μ‚¬μš©ν•˜κ³  μžˆμ§€λ§Œ 이둠은 Lambda λ“±μ—μ„œλ„ λ™μΌν•©λ‹ˆλ‹€. 관심 μžˆλŠ” μ‚¬λžŒμ΄ 있으면 https://httptoolkitμ—μ„œ 이 μž‘μ—…μ„ μˆ˜ν–‰ν•˜λŠ” 방법에 λŒ€ν•œ μžμ„Έν•œ λ‚΄μš©μ΄ ν¬ν•¨λœ κ²Œμ‹œλ¬Όμ„ μž‘μ„±ν–ˆμŠ΅λ‹ˆλ‹€. tech/blog/netlify-function-error-reporting-with-sentry/

ν˜„μž¬ λͺ¨λ“  λžŒλ‹€μ—μ„œ 이 λ„μš°λ―Έ λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

@pimterry 이것은 기본적으둜 @LinusU κ°€ μ œμ•ˆν•œ 것과 λ™μΌν•œ μ†”λ£¨μ…˜μ΄ μ•„λ‹™λ‹ˆκΉŒ? λ‚˜λŠ” 그것을 μ‹œλ„ν–ˆμ§€λ§Œ μΆ”κ°€ 데이터도 보내지 μ•ŠμŠ΅λ‹ˆλ‹€.

이 μ ‘κ·Ό 방식 은 μ§€κΈˆκΉŒμ§€ @ondrowan에 νš¨κ³Όκ°€ μžˆμ—ˆμŠ΅λ‹ˆλ‹€.

@ondrowan λ™μΌν•˜μ§€λ§Œ μˆ˜λ™μœΌλ‘œ ν˜„μž¬ λ²”μœ„λ₯Ό 작고 ν¬ν•¨ν•©λ‹ˆλ‹€. 제 μƒκ°μ—λŠ” μ˜ˆμ™Έ μž‘μ—…μ„ μˆ˜ν–‰ν•˜κΈ°μ— μΆ©λΆ„ν•΄μ•Όν•©λ‹ˆλ‹€. 이전 λ²„μ „μ—μ„œλŠ” λ ˆμ΄λΈ”μ΄ μ§€μ •λ˜μ§€ μ•Šμ€ μ΄λ²€νŠΈκ°€ λ°œμƒν–ˆμœΌλ©° 이제 이 λ³€κ²½μœΌλ‘œ 인해 μ˜ˆμ™Έκ°€ λͺ¨λ“  μΆ”κ°€ 일반 μ„ΈλΆ€ 정보와 ν•¨κ»˜ λ°œμƒν•©λ‹ˆλ‹€.

@vietbui @albinekb @Andriy-Kulak @LinusU @dwelch2344 @jviolas @rreynier @guillaumekh @rdsedmundo @ondrowan @pimterry @zeusdeux λˆ„κ°€ μ—¬μ „νžˆ 이 μ‚¬μš© 사둀에 관심이 μžˆλŠ”μ§€ 잘 λͺ¨λ₯΄κ²  μœΌλ―€λ‘œ μ „ν™” ν•˜μ§€ μ•Šμ•„λ„ λ˜λŠ” 점 μ–‘ν•΄ λΆ€νƒλ“œλ¦½λ‹ˆλ‹€.

4.6.0 μ‹œμž‘ν•˜λ©΄ 더 이상 client/hub λŒ„μŠ€κ°€ μ—†μŠ΅λ‹ˆλ‹€. captureX λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•œ λ‹€μŒ Sentry.flush() λ₯Ό μ‚¬μš©ν•˜μ—¬ λͺ¨λ“  것이 μ„œλ²„λ‘œ μ „μ†‘λ˜λ©΄ 응닡을 기닀릴 수 μžˆμŠ΅λ‹ˆλ‹€. λͺ¨λ“  λ²”μœ„/μΆ”κ°€ λ°μ΄ν„°λŠ” 개발자 μƒν˜Έ μž‘μš© 없이 λ³΄μ‘΄λ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€.

λ‹€μŒμ€ 성곡/μ‹œκ°„ 초과 μš”μ²­μ΄ μžˆλŠ” μ˜ˆμž…λ‹ˆλ‹€.

image

도움이 되기λ₯Ό λ°”λžλ‹ˆλ‹€! :)

멋진!

Lambda 및 기타 μ„œλ²„λ¦¬μŠ€ μ†”λ£¨μ…˜μ—μ„œ μ˜ˆμ™Έλ₯Ό μΊ‘μ²˜ν•˜κΈ° μœ„ν•œ μ΅œμ†Œν•œμ˜ νŒ¨ν‚€μ§€λ₯Ό λ§Œλ“€ κ³„νšμ΄ μžˆμŠ΅λ‹ˆκΉŒ? λ‚˜λŠ” 그것이 μ—¬μ „νžˆ 정말 쒋은 μΆ”κ°€κ°€ 될 것이라고 μƒκ°ν•©λ‹ˆλ‹€ ❀️

@LinusU 희망적으둜 예, ν•˜μ§€λ§Œ μš°λ¦¬λŠ” μ§€κΈˆ λ‹€λ₯Έ μ–Έμ–΄ SDK둜 가득 μ°¨ μžˆμŠ΅λ‹ˆλ‹€ πŸ˜…

κ°€λŠ₯ν•œ λͺ¨λ“  μ†”λ£¨μ…˜μ— κ°μ‚¬λ“œλ¦½λ‹ˆλ‹€. μ—¬κΈ° 와주신 λͺ¨λ“  λΆ„λ“€κ»˜ κ°μ‚¬λ“œλ¦½λ‹ˆλ‹€.

await Sentry.flush() λ₯Ό μ‚¬μš©ν•˜μ—¬ 보λ₯˜ 쀑인 λͺ¨λ“  μš”μ²­μ„ λ³΄λƒ…λ‹ˆλ‹€. 이것은 4.6.x 에 λ„μž…λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

이 글을 λ‹«κ³  λˆ„λ½λœ 것이 μžˆλŠ” 경우λ₯Ό λŒ€λΉ„ν•˜μ—¬ 자유둭게 μƒˆ 호λ₯Ό μ—¬μ‹­μ‹œμ˜€(κ·ΈλŸ¬λ‚˜ 이 μŠ€λ ˆλ“œλŠ” 이미 맀우 κΉλ‹ˆλ‹€).

건배 πŸ‘ πŸŽ‰

@kamilogorek μ•ˆλ…•ν•˜μ„Έμš”! 참고둜 μ €λŠ” 이전 ν•΄κ²° 방법 λŒ€μ‹  λ‚΄ μ•±μ—μ„œ Sentry.flush λ₯Ό μ‚¬μš©ν•˜κ³  있으며 였λ₯˜κ°€ λ³΄κ³ λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. ν˜„μž¬ μ—…λ°μ΄νŠΈλœ flush λ©”μ„œλ“œ μ—μ„œ 이전 ν•΄κ²° λ°©λ²•μœΌλ‘œ 되돌리고 μžˆμŠ΅λ‹ˆλ‹€.

@zeusdeux 이에 λŒ€ν•œ 디버그 정보/재판 사둀λ₯Ό μ œκ³΅ν•  수 μžˆλŠ” 방법이 μžˆμŠ΅λ‹ˆκΉŒ?
버퍼에 이벀트λ₯Ό μΆ”κ°€ν•˜λŠ” captureException λ©”μ„œλ“œλ₯Ό μž¬μ •μ˜ν•˜κ³  flush λ°˜ν™˜ 값에 await λ₯Ό μΆ”κ°€ν•΄μ•Ό ν•©λ‹ˆλ‹€. "일반적인 방법"으둜 μ‚¬μš©ν•΄ λ³΄μ…¨μŠ΅λ‹ˆκΉŒ?

@kamilogorek 디버그 정보가 있으면 μ’‹κ² μ§€λ§Œ λ‘œκ·Έμ— 아무것도 μ—†μŠ΅λ‹ˆλ‹€. λ‚˜λŠ” 항상 μž¬μ •μ˜λœ captureException μ—μ„œ await 을 ν–ˆμŠ΅λ‹ˆλ‹€ . 일반적인 λ°©λ²•μœΌλ‘œ captureException λ₯Ό μž¬μ •μ˜ν•˜μ§€ μ•Šκ³  μ˜λ―Έν•©λ‹ˆκΉŒ?

@zeusdeux μ •ν™•νžˆ, μž¬μ •μ˜ 없이 κΈ°λ³Έ Sentry.captureException(error) λ₯Ό ν˜ΈμΆœν•˜λ©΄ λ©λ‹ˆλ‹€.

λ”°λΌμ„œ λ„μš°λ―ΈλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

import * as Sentry from '@sentry/node'

export function init({ host, method, lambda, deployment }) {
  const environment = host === process.env.PRODUCTION_URL ? 'production' : host

  Sentry.init({
    dsn: process.env.SENTRY_DSN,
    environment,
    beforeSend(event, hint) {
      if (hint && hint.originalException) {
        // eslint-disable-next-line
        console.log('Error:', hint.originalException);
      }
      return event;
    }
  })

  Sentry.configureScope(scope => {
    scope.setTag('deployment', deployment)
    scope.setTag('lambda', lambda)
    scope.setTag('method', method)
  })
}

μ½”λ“œμ—μ„œ λ‹€μŒκ³Ό 같이 ν˜ΈμΆœν•©λ‹ˆλ‹€.

import * as Sentry from '@sentry/node'

try {
  // ...
} catch (err) {
  Sentry.captureException(err);
  await Sentry.flush(2000);
  return respondWithError('Something went wrong', 500);
}

@kamilogorek 해보고 λ‹€μ‹œ λ³΄κ³ ν•˜κ² μŠ΅λ‹ˆλ‹€. λ˜ν•œ beforeSend 에 λŒ€ν•œ νŒμ„ μ£Όμ…”μ„œ κ°μ‚¬ν•©λ‹ˆλ‹€ ^_^

await Sentry.flush(2000);

도 ~not~ λ‚˜λ₯Ό μœ„ν•΄ μΌν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

@tanduong μž¬ν˜„ μΌ€μ΄μŠ€λ₯Ό μ œκ³΅ν•  수 μžˆμŠ΅λ‹ˆκΉŒ? νš¨κ³Όκ°€ μ—†λ‹€κ³  λ§ν•˜λŠ” κ²ƒλ§ŒμœΌλ‘œλŠ” 도움이 λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€ πŸ˜‚

@kamilogorek 사싀, λ‚˜λŠ” 그것을 방금 μ•Œμ•˜λ‹€.

await Sentry.getCurrentHub().getClient().close(2000)

λ‚΄ λžŒλ‹€ ν•¨μˆ˜κ°€ VPC에 μ—°κ²°λ˜μ–΄ 있기 λ•Œλ¬Έμ— μž‘λ™ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

λ‚˜λŠ” 그것을 ν™•μΈν•œλ‹€

await Sentry.flush(2000);

μ‹€μ œλ‘œ μž‘λ™ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

BTW, 그러면 VPCμ—μ„œ λžŒλ‹€λ₯Ό μ–΄λ–»κ²Œ μ²˜λ¦¬ν• κΉŒμš”? NAT κ²Œμ΄νŠΈμ›¨μ΄μ— μ—°κ²°ν•˜μ‹œκ² μŠ΅λ‹ˆκΉŒ? λ‚˜λŠ” 단지 Sentryλ₯Ό μ›ν•˜μ§€λ§Œ 곡용 인터넷은 μ›ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

@tanduong SentryλŠ” 곡용 인터넷에 μžˆμœΌλ―€λ‘œ λžŒλ‹€κ°€ VPC λ‚΄μ—μ„œ μ‹€ν–‰λ˜λŠ” 경우 NAT κ²Œμ΄νŠΈμ›¨μ΄κ°€ μžˆμ–΄μ•Ό ν•©λ‹ˆλ‹€. 그렇지 μ•ŠμœΌλ©΄ ν˜ΈμŠ€νŒ…λœ Sentry μ˜΅μ…˜μ„ 탐색해야 ν•©λ‹ˆλ‹€.

flush(2000) 은 μ‹€μ œλ‘œ 무엇을 ν•˜κ³  μžˆμŠ΅λ‹ˆκΉŒ? 이 μ½”λ“œλŠ” λŒ€λΆ€λΆ„ 잘 μž‘λ™ν–ˆμ§€λ§Œ μ§€κΈˆμ€ λͺ‡ captureMessage 호좜이 λ™μ‹œμ— λ°œμƒν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. 맀번 μ‹œκ°„μ΄ μ΄ˆκ³Όλ©λ‹ˆλ‹€!

μœ μ„ μ„ 톡해 λ‚΄λΆ€ λ©”μ‹œμ§€ λŒ€κΈ°μ—΄ ν”ŒλŸ¬μ‹œ

μ•Œκ² μŠ΅λ‹ˆλ‹€. λ‚΄ λ¬Έμ œλŠ” ν”ŒλŸ¬μ‹œ ν•  λ‹€λ₯Έ 것이 없을 λ•Œμ΄ 약속이 λ°˜ν™˜λ˜μ§€ μ•ŠλŠ”λ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€. λž˜ν•‘λœ captureException fn을 λ™μ‹œμ— μ‹€ν–‰ν•  λ•Œλ§ˆλ‹€ ν•Έλ“€λŸ¬κ°€ μ‹œκ°„ μ΄ˆκ³Όλ©λ‹ˆλ‹€.

export const captureMessage = async (
  message: string,
  extras?: any,
): Promise<boolean> =>
  new Promise((resolve) => {
    Sentry.withScope(async (scope) => {
      if (typeof extras !== 'undefined') {
        scope.setExtras(extras)
      }
      Sentry.captureMessage(message)
      await Sentry.flush(2000)
      resolve(true)
    })
  })

await Sentry.flush() λŠ” 첫 번째 captureMessage 호좜 후에 μ‹€μ œλ‘œ μ™„λ£Œλ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

@enapupe와 λΉ„μŠ·ν•œ λ¬Έμ œκ°€ μžˆλ‹€κ³  μƒκ°ν•©λ‹ˆλ‹€. await client.flush(2000); λ₯Ό λ³‘λ ¬λ‘œ ν˜ΈμΆœν•˜λ©΄ 첫 번째 μ•½μ†λ§Œ ν•΄κ²°λ©λ‹ˆλ‹€. μ΄λŠ” ν•Έλ“€λŸ¬μ— λŒ€ν•œ μ—¬λŸ¬ λ™μ‹œ 호좜 μ‚¬μ΄μ—μ„œ ν΄λΌμ΄μ–ΈνŠΈκ°€ μž¬μ‚¬μš©λ˜λŠ” AWS λžŒλ‹€ μ»¨ν…μŠ€νŠΈμ—μ„œ λ°œμƒν•  수 μžˆμŠ΅λ‹ˆλ‹€.

λ‹€μŒκ³Ό 같은 μ½”λ“œλ₯Ό μ‚¬μš©ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

 let client = Sentry.getCurrentHub().getClient();
  if (client) {
    // flush the sentry client if it has any events to send
    log('begin flushing sentry client');
    try {
      await client.flush(2000);
    } catch (err) {
      console.error('sentry client flush error:', err);
    }
    log('end flushing sentry client');
  }

κ·ΈλŸ¬λ‚˜ λΉ λ₯΄κ²Œ λžŒλ‹€ ν•¨μˆ˜λ₯Ό 두 번 ν˜ΈμΆœν•˜λ©΄ λ‹€μŒκ³Ό 같은 κ²°κ³Όκ°€ λ‚˜νƒ€λ‚©λ‹ˆλ‹€.

  app begin flushing sentry client +2ms
  app begin flushing sentry client +0ms
  app end flushing sentry client +2ms

두 번째 약속은 μ ˆλŒ€ ν•΄κ²°λ˜μ§€ μ•ŠλŠ” 것을 λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€.

@esetnik 이에 λŒ€ν•œ 문제λ₯Ό μ œμΆœν–ˆμŠ΅λ‹ˆλ‹€: https://github.com/getsentry/sentry-javascript/issues/2131
ν˜„μž¬ ν•΄κ²° 방법은 항상 ν•΄κ²°λ˜λŠ” 래퍼 ν”ŒλŸ¬μ‹œ fnμž…λ‹ˆλ‹€(μ‹œκ°„ 초과 κΈ°μ€€).

const resolveAfter = (ms: number) =>
  new Promise((resolve) => setTimeout(resolve, ms))

const flush = (timeout: number) =>
  Promise.race([resolveAfter(timeout), Sentry.flush(timeout)])

@enapupe #2131μ—μ„œ ν•΄κ²° 방법에 λŒ€ν•œ λ©”λͺ¨λ₯Ό μΆ”κ°€ν–ˆμŠ΅λ‹ˆλ‹€. λ‚˜λŠ” 그것이 λ™μ‹œ ν”ŒλŸ¬μ‹œμ—μ„œ μ„±λŠ₯ μ €ν•˜λ₯Ό μΌμœΌν‚¬ 것이라고 λ―ΏμŠ΅λ‹ˆλ‹€.

λˆ„κ΅°κ°€ λ¬Έμ œκ°€ μžˆλŠ” 경우.
이것은 μ•„λ¦„λ‹΅κ²Œ μž‘λ™ν•©λ‹ˆλ‹€.

@SarasArya @HazAT
μš°μ„ ... μ†”λ£¨μ…˜μ„ κ³΅μœ ν•΄ μ£Όμ…”μ„œ κ°μ‚¬ν•©λ‹ˆλ‹€! :)
configureScope λ©”μ†Œλ“œμ˜ 콜백이 ν•˜λ‚˜ μžˆλŠ”λ° captureException 전에 ν˜ΈμΆœλ˜μ–΄μ•Ό ν•˜μ§€λ§Œ λ™μΌν•œ "μŠ€λ ˆλ“œ"μ—μ„œ μˆ˜ν–‰λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
이것은 경쟁 쑰건의 μΆœν˜„μœΌλ‘œ μ΄μ–΄μ§ˆ 수 μ—†μ—ˆμŠ΅λ‹ˆκΉŒ?

@cibergarri κ·Έλ ‡κ²Œ μƒκ°ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. μ €μ—κ²Œ λ™κΈ°μ μœΌλ‘œ λ³΄μž…λ‹ˆλ‹€. 거기에 비동기 λ©”μ„œλ“œκ°€ μžˆλŠ” 경우 경쟁 쑰건이 μžˆμ„ 수 μžˆμŠ΅λ‹ˆλ‹€.
μ—¬κΈ°μ—μ„œ λ™μΌν•œ 일이 λ°œμƒν•˜λŠ” λ°°μ—΄μ˜ .mapκ³Ό κ°™λ‹€κ³  μƒκ°ν•˜μ‹­μ‹œμ˜€. μ£Όμœ„μ— 머리λ₯Ό κ°μ‹ΈλŠ” λ¬Έμ œκ°€ μžˆλŠ” 경우. 도움이 되기λ₯Ό λ°”λžλ‹ˆλ‹€.

λ„€, κ·Έλ ‡κ²Œ ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

μ—…λ°μ΄νŠΈ: SentryλŠ” 이제 Node/Lambda ν™˜κ²½μ— λŒ€ν•œ μžλ™ν™”λœ 였λ₯˜ 캑처λ₯Ό μ§€μ›ν•©λ‹ˆλ‹€. https://docs.sentry.io/platforms/node/guides/aws-lambda/

λ‹€μŒκ³Ό 같이 @sentry/serverlessλ₯Ό μ‚¬μš©ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

const Sentry = require("@sentry/serverless");
Sentry.AWSLambda.init({
  dsn: process.env.SENTRY_DSN,
  tracesSampleRate: 1.0,
  environment: appEnv
});

exports.main = Sentry.AWSLambda.wrapHandler(async (event, context) => {
     try{
           //my code
     }catch(error){
          Sentry.captureException(error);
          await Sentry.flush(3000);
     }

});

λžŒλ‹€μ—μ„œλŠ” μž‘λ™ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
λ‚΄ ν…ŒμŠ€νŠΈ ν™˜κ²½μ—μ„œλŠ” μž‘λ™ν–ˆμ§€λ§Œ λ™μ‹œ 싀행이 많고 μ»¨ν…Œμ΄λ„ˆκ°€ μž¬μ‚¬μš©λ˜λŠ” μ œν’ˆμ—μ„œλŠ” 총 μ–‘μ˜ μ•½ 10%만 λ‘œκΉ…ν•©λ‹ˆλ‹€.

μ–΄λ–€ μΆ©κ³ ?

@armando25723

μ˜ˆμ™Έ 이벀트λ₯Ό μžƒλŠ” 것을 μ–΄λ–»κ²Œ μΈ‘μ •ν–ˆλŠ”μ§€ μ•Œλ €μ£Όμ‹­μ‹œμ˜€. κ·ΈλŸ¬ν•œ μ†μ‹€λœ μ˜ˆμ™Έκ°€ μ–΄λ–»κ²Œ λ°œμƒν–ˆλŠ”μ§€μ— λŒ€ν•œ μ½”λ“œ μƒ˜ν”Œμ΄ μžˆμŠ΅λ‹ˆκΉŒ? 더 λ§Žμ€ μ»¨ν…μŠ€νŠΈκ°€ ν•„μš”ν•©λ‹ˆλ‹€.

const Sentry = require("@sentry/serverless"); // "version": "5.27.3"
Sentry.AWSLambda.init({
  dsn: process.env.SENTRY_DSN,
  tracesSampleRate: 1.0,
  environment: appEnv
});
exports.main = Sentry.AWSLambda.wrapHandler(async (event, context) => {
     try{
           throw new Error('Test Error');
     }catch(error){
          Sentry.captureException(error);
          await Sentry.flush(3000);
     }
});

무슨 일이야?
호좜 μ‚¬μ΄μ˜ 짧은 κ°„κ²©μœΌλ‘œ ν•¨μˆ˜κ°€ μ—¬λŸ¬ 번 호좜되면 μ΄λ²€νŠΈλŠ” ν•œ 번만 κΈ°λ‘λ©λ‹ˆλ‹€.
호좜 μ‚¬μ΄μ˜ μ‹œκ°„ 간격이 더 크면 λͺ¨λ“  μ΄λ²€νŠΈκ°€ κΈ°λ‘λ©λ‹ˆλ‹€.

호좜이 μž¬μ‚¬μš©λœ μ»¨ν…Œμ΄λ„ˆμ— λŒ€ν•΄ λ¬Έμ œκ°€ μžˆλ‹€κ³  κ°€μ •ν•©λ‹ˆλ‹€.

λ‚˜λŠ” λ˜ν•œ μ‹œλ„ν–ˆλ‹€
await Sentry.captureException(error);
그리고:
await Sentry.flush();
그리고 ν”ŒλŸ¬μ‹± 없이
같은 κ²°κ³Ό

@marshall-lee 무엇을 μΆ”μ²œν•˜μ‹œλ‚˜μš”? 문제λ₯Ό λ§Œλ“€λ©΄ μ—¬κΈ°μ—μ„œ 멈μΆ₯λ‹ˆλ‹€.

@armando25723 이 이벀트λ₯Ό λ³΄λ‚΄λŠ” λ™μ•ˆ μ„œλ²„κ°€ 429(μ˜ˆμ™Έκ°€ λ„ˆλ¬΄ 많음)둜 μ‘λ‹΅ν•˜λŠ” 것 κ°™μŠ΅λ‹ˆλ‹€. ν• λ‹ΉλŸ‰/속도 μ œν•œ μ‹œλ‚˜λ¦¬μ˜€λ₯Ό μ΄ˆκ³Όν•˜λŠ” 경우 이λ₯Ό λ˜μ§‘λ‹ˆλ‹€. 순차적으둜 였λ₯˜λ₯Ό λ³΄λ‚΄λŠ”μ§€ μ•„λ‹ˆλ©΄ ν• λ‹ΉλŸ‰μ„ μ΄ˆκ³Όν•˜λŠ”μ§€ μ•Œκ³  μžˆμŠ΅λ‹ˆκΉŒ? 이것이 μ‹€μ œ 였λ₯˜ μ΄λ²€νŠΈκ°€ μ‚­μ œλ˜κ³  프리 티어에 λŒ€ν•œ 5k μ œν•œ 미만이라고 μƒκ°ν•˜λŠ” 경우 μΆ”κ°€λ‘œ 디버그할 수 μžˆμŠ΅λ‹ˆλ‹€.

@ajjindal λ‹€λ₯Έ λͺ¨λ“  ν”„λ‘œμ νŠΈλŠ” sentry와 잘 μž‘λ™ν•©λ‹ˆλ‹€. 쑰직 μŠ¬λŸ¬κ·ΈλŠ” "alegra"이고 ν”„λ‘œμ νŠΈ 이름은 #mail-micros μ•„λž˜μ˜ mail-dispatch-serverlessμž…λ‹ˆλ‹€. μš°λ¦¬λŠ” μ˜€λž«λ™μ•ˆ μ„ΌνŠΈλ¦¬λ₯Ό μ‚¬μš©ν•΄ μ™”μ§€λ§Œ μ„œλ²„λ¦¬μŠ€λŠ” μ²˜μŒμž…λ‹ˆλ‹€. 이것은 프리 ν‹°μ–΄κ°€ μ•„λ‹ˆλ―€λ‘œ μ •ν™•νžˆ μ–΄λ–€ ν”Œλžœμ„ μ‚¬μš©ν•˜κ³  μžˆλŠ”μ§€ λ§μ”€λ“œλ¦΄ μˆ˜λŠ” μ—†μ§€λ§Œ μœ λ£Œμž…λ‹ˆλ‹€.
더 λ””λ²„κΉ…ν•˜λŠ” 데 도움이 λœλ‹€λ©΄ 쒋을 κ²ƒμž…λ‹ˆλ‹€.
λ‹΅λ³€ κ°μ‚¬ν•©λ‹ˆλ‹€ : )

PD: νŒ€ν”Œλžœ

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