μλ ν, μ¬λ 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
ν€μ΄, κ³ λ§μ! :)
κ·Έλλ μ ννκ°μ? 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 κ° μ§μ ν μ€νΈνμΌλ©° 컨ν μ€νΈ νμΈμ΄ μ λλ‘ μλνλ κ² κ°μ΅λλ€. λΉμ μ κΈ°λ₯/ꡬμ±μ 무μμ λκΉ?
μλ νμΈμ @kamilogorek λμμ£Όμ μ κ°μ¬ν©λλ€!
Hello Worldλ‘ μ»μ μ μλ κ²μ 볡μ νμΌλ―λ‘ νλ₯ν©λλ€.
κ·Έλ¬λ 컨ν μ€νΈ λ³μκ° μμ΅λλ€. λ²μμμ λ³μμ κ°μ λ³Ό μ μλ κ²μ²λΌ? μλλ©΄ νμ΄μ¬ κΈ°λ₯λ§ μμ΅λκΉ?
λν λ΄κ° λ°κ³ μλ λ 볡μ‘ν μ€λ₯λ λ°μ΄ν°λ² μ΄μ€μ μ°κΈ°/μ½κΈ°λ₯Ό ν λ μ€νΈλ¦Ό/μ΄λ²€νΈμ μ€λ₯κ° μλ κ² κ°μ΅λλ€.
μλ₯Ό λ€μ΄ μλ μ€ν¬λ¦°μ·μμλ μ΄λ€ ν¨μμμ νΈμΆλμλμ§μ‘°μ°¨ μ μ μμ΅λλ€.
λΉμ μ μΆμ²μ 무μμ λκΉ? μλ ν¨μ μ²λ¦¬κΈ°μ νΈμΆμ ν¬ν¨νλ λ κΈ΄ StackTraceλ₯Ό μ»λ λ°©λ²μ΄ μμ΅λκΉ? μλλ©΄ λΉ΅κ°λ£¨λ₯Ό λ μΆκ°ν΄μΌ νλμ?
λν μ΄λ¬ν μμ€ μ½λλ₯Ό μ°Ύμ μ μμ μ€λ₯λ‘ μΈν΄ λ¬΄μ¨ μΌμ΄ μΌμ΄λκ³ μλμ§ μμλκΉ?
κ·Έλ¬λ 컨ν μ€νΈ λ³μκ° μμ΅λλ€. λ²μμμ λ³μμ κ°μ λ³Ό μ μλ κ²μ²λΌ? μλλ©΄ νμ΄μ¬ κΈ°λ₯λ§ μμ΅λκΉ?
νμ΄μ¬λ§μ κΈ°λ₯μ λλ€. λΆννλ 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 κ°μ¬ν©λλ€!
λͺ κ°μ§ μκ°:
ctx.req
λ° `ctx.resμ μ μ₯λ λλ©μΈμ μ€μ λ
Έλ req
λ° res
λ₯Ό λ°μΈλ©ν μ μμ΅λλ€.
req
λ
Έλλ₯Ό parseRequest
λ‘ μ λ¬ν μ μμ΅λλ€.
μλμΌλ‘ μ€λ₯λ₯Ό μ‘μ ν 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);
μλ΅λ§ λ°ννκ³ μ€μ μ§μ€μ μ€λ₯ μ²λ¦¬κΈ°μ μ€λ₯λ₯Ό μ λ¬νμ§ μμΌλ €λ κ²½μ°κ° μλκΉμ?
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