Skip to content

Commit 43b383c

Browse files
authored
feat(firebase): Instrument cloud functions for firebase v2 (#17952)
Closes: #17861 This adds - instrumentation of Cloud Functions for Firebase (v2) along side the Firestore integration. It can be used with the `Sentry.firebaseIntegration()` (this is atm not documented in the docs and got added in #16719, but will be added right after this has been merged. See getsentry/sentry-docs#15247). - The test app for Firebase has been rewritten and updated since it requires a little special setup. <details> <summary>Supported functions</summary> <ul> <li>onRequest</li> <li>onCall</li> <li>onDocumentCreated</li> <li>onDocumentUpdated</li> <li>onDocumentDeleted</li> <li>onDocumentWritten</li> <li>onDocumentCreatedWithAuthContext</li> <li>onDocumentUpdatedWithAuthContext</li> <li>onDocumentDeletedWithAuthContext</li> <li>onDocumentWrittenWithAuthContext</li> <li>onSchedule</li> <li>onObjectFinalized</li> <li>onObjectArchived</li> <li>onObjectDeleted</li> <li>onObjectMetadataUpdated</li> </ul> </details> Bear in mind that the OTel attributes for FaaS are still in [Development](https://opentelemetry.io/docs/specs/semconv/faas/faas-spans/) and could change or be removed over time (not sure if we should then even add them in here at this point in time).
1 parent 152b9d4 commit 43b383c

File tree

21 files changed

+667
-80
lines changed

21 files changed

+667
-80
lines changed

.size-limit.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ module.exports = [
240240
import: createImport('init'),
241241
ignore: [...builtinModules, ...nodePrefixedBuiltinModules],
242242
gzip: true,
243-
limit: '157 KB',
243+
limit: '158 KB',
244244
},
245245
{
246246
name: '@sentry/node - without tracing',

dev-packages/e2e-tests/test-applications/node-firebase/.firebaserc

Lines changed: 0 additions & 5 deletions
This file was deleted.
Lines changed: 33 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,50 @@
1-
## Assuming you already have installed docker desktop or orbstack etc. or any other docker software
1+
<center>
2+
<a href="https://firebase.google.com/" target="_blank">
3+
<img src="https://firebase.google.com/static/downloads/brand-guidelines/SVG/logo-standard.svg" alt="Firebase" width="200">
4+
</a>
5+
</center>
26

3-
### Enabling / authorising firebase emulator through docker
7+
## Description
48

5-
1. Run the docker
9+
[Firebase](https://firebase.google.com/) starter repository with Cloud Functions for Firebase and Firestore.
610

7-
```bash
8-
pnpm docker
9-
```
10-
11-
2. In new tab, enter the docker container by simply running
11+
## Project setup
1212

13-
```bash
14-
docker exec -it sentry-firebase bash
13+
```sh
14+
$ pnpm install
1515
```
1616

17-
3. Now inside docker container run
17+
## Compile and run the project
1818

19-
```bash
20-
firebase login
19+
```sh
20+
$ pnpm dev # builds the functions and firestore app
21+
$ pnpm emulate
22+
$ pnpm start # run the firestore app
2123
```
2224

23-
4. You should now see a long link to authenticate with google account, copy the link and open it using your browser
24-
5. Choose the account you want to authenticate with
25-
6. Once you do this you should be able to see something like "Firebase CLI Login Successful"
26-
7. And inside docker container you should see something like "Success! Logged in as <here is the email you have chosen>"
27-
8. Now you can exit docker container
28-
29-
```bash
30-
exit
31-
```
25+
## Run tests
3226

33-
9. Switch back to previous tab, stop the docker container (ctrl+c).
34-
10. You should now be able to run the test, as you have correctly authenticated the firebase emulator
27+
Either run the tests directly:
3528

36-
### Preparing data for CLI
37-
38-
1. Please authorize the docker first - see the previous section
39-
2. Once you do that you can generate .env file locally, to do that just run
40-
41-
```bash
42-
npm run createEnvFromConfig
29+
```sh
30+
$ pnpm test:build
31+
$ pnpm test:assert
4332
```
4433

45-
3. It will create a new file called ".env" inside folder "docker"
46-
4. View the file. There will be 2 params CONFIG_FIREBASE_TOOLS and CONFIG_UPDATE_NOTIFIER_FIREBASE_TOOLS.
47-
5. Now inside the CLI create a new variable under the name CONFIG_FIREBASE_TOOLS and
48-
CONFIG_UPDATE_NOTIFIER_FIREBASE_TOOLS - take values from mentioned .env file
49-
6. File .env is ignored to avoid situation when developer after authorizing firebase with private account will
50-
accidently push the tokens to github.
51-
7. But if we want the users to still have some default to be used for authorisation (on their local development) it will
52-
be enough to commit this file, we just have to authorize it with some "special" account.
34+
Or run develop while running the tests directly against the emulator. Start each script in a separate terminal:
5335

54-
**Some explanation towards environment settings, the environment variable defined directly in "environments" takes
55-
precedence over .env file, that means it will be safe to define it in CLI and still keeps the .env file.**
36+
```sh
37+
$ pnpm dev
38+
$ pnpm emulate
39+
$ pnpm test --ui
40+
```
5641

57-
### Scripts - helpers
42+
The tests will run against the Firebase Emulator Suite.
5843

59-
- createEnvFromConfig - it will use the firebase docker authentication and create .env file which will be used then by
60-
docker whenever you run emulator
61-
- createConfigFromEnv - it will use '.env' file in docker folder to create .config for the firebase to be used to
62-
authenticate whenever you run docker, Docker by default loads .env file itself
44+
## Resources
6345

64-
Use these scripts when testing and updating the environment settings on CLI
46+
- [Firebase](https://firebase.google.com/)
47+
- [Firebase Emulator Suite](https://firebase.google.com/docs/emulator-suite)
48+
- [Firebase SDK](https://firebase.google.com/docs/sdk)
49+
- [Firebase Functions](https://firebase.google.com/docs/functions)
50+
- [Firestore](https://firebase.google.com/docs/firestore)

dev-packages/e2e-tests/test-applications/node-firebase/firebase.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,12 @@
1616
"enabled": true
1717
},
1818
"singleProjectMode": true
19-
}
19+
},
20+
"functions": [
21+
{
22+
"source": "functions",
23+
"codebase": "default",
24+
"ignore": ["node_modules", ".git", "firebase-debug.log", "firebase-debug.*.log", "*.local"]
25+
}
26+
]
2027
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"name": "firestore-app",
3+
"private": true,
4+
"scripts": {
5+
"build": "tsc",
6+
"dev": "tsc --build --watch",
7+
"start": "node ./dist/app.js"
8+
},
9+
"dependencies": {
10+
"@firebase/app": "^0.13.1",
11+
"@sentry/node": "latest || *",
12+
"express": "^4.18.2",
13+
"firebase": "^12.0.0"
14+
},
15+
"devDependencies": {
16+
"@types/express": "^4.17.13",
17+
"@types/node": "^22.13.14",
18+
"typescript": "5.9.3"
19+
}
20+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"extends": "../tsconfig.json",
3+
"compilerOptions": {
4+
"outDir": "dist",
5+
"skipLibCheck": true
6+
},
7+
"include": ["src"]
8+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"name": "functions",
3+
"scripts": {
4+
"build": "tsc",
5+
"dev": "tsc --build --watch"
6+
},
7+
"engines": {
8+
"node": "20"
9+
},
10+
"main": "dist/index.js",
11+
"dependencies": {
12+
"firebase-admin": "^12.6.0",
13+
"firebase-functions": "^6.0.1",
14+
"@sentry/node": "latest || *"
15+
},
16+
"devDependencies": {
17+
"typescript": "5.9.3"
18+
}
19+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import './init';
2+
3+
import { onDocumentCreated, onDocumentCreatedWithAuthContext } from 'firebase-functions/firestore';
4+
import { onRequest } from 'firebase-functions/https';
5+
import * as logger from 'firebase-functions/logger';
6+
import { setGlobalOptions } from 'firebase-functions/options';
7+
import * as admin from 'firebase-admin';
8+
9+
setGlobalOptions({ region: 'default' });
10+
11+
admin.initializeApp();
12+
13+
const db = admin.firestore();
14+
15+
export const helloWorld = onRequest(async (request, response) => {
16+
logger.info('Hello logs!', { structuredData: true });
17+
18+
response.send('Hello from Firebase!');
19+
});
20+
21+
export const unhandeledError = onRequest(async (request, response) => {
22+
throw new Error('There is an error!');
23+
});
24+
25+
export const onCallSomething = onRequest(async (request, response) => {
26+
const data = {
27+
name: request.body?.name || 'Sample Document',
28+
timestamp: performance.now(),
29+
description: request.body?.description || 'Created via Cloud Function',
30+
};
31+
32+
await db.collection('documents').add(data);
33+
34+
logger.info('Create document!', { structuredData: true });
35+
36+
response.send({ message: 'Document created!' });
37+
});
38+
39+
export const onDocumentCreate = onDocumentCreated('documents/{documentId}', async event => {
40+
const documentId = event.params.documentId;
41+
42+
await db.collection('documents').doc(documentId).update({
43+
processed: true,
44+
processedAt: new Date(),
45+
});
46+
});
47+
48+
export const onDocumentCreateWithAuthContext = onDocumentCreatedWithAuthContext('documents/{documentId}', async () => {
49+
// noop
50+
});

0 commit comments

Comments
 (0)