Skip to content

Commit aa52d6c

Browse files
onurtemizkans1gr1d
andauthored
feat(node): Add firebase integration (#16719)
Continued work on #13954 Resolves: #13678 Adds instrumentation for Firebase / Firestore queries. Updates on top of #13954: - Removed dependencies to firebase packages (inlined simplified types) - #13954 (comment) - Imported OTEL Semconv keys from the updated OTEL package - Set `SEMANTIC_ATTRIBUTE_SENTRY_OP` to `db.query` at all times --------- Co-authored-by: Sigrid Huemer <32902192+s1gr1d@users.noreply.github.com>
1 parent ee63f5f commit aa52d6c

File tree

28 files changed

+1041
-0
lines changed

28 files changed

+1041
-0
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"projects": {
3+
"default": "sentry-firebase-e2e-test-f4ed3"
4+
}
5+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# compiled output
2+
/dist
3+
/node_modules
4+
/build
5+
6+
# Logs
7+
logs
8+
*.log
9+
npm-debug.log*
10+
pnpm-debug.log*
11+
yarn-debug.log*
12+
yarn-error.log*
13+
lerna-debug.log*
14+
15+
# OS
16+
.DS_Store
17+
18+
# Tests
19+
/coverage
20+
/.nyc_output
21+
22+
# IDEs and editors
23+
/.idea
24+
.project
25+
.classpath
26+
.c9/
27+
*.launch
28+
.settings/
29+
*.sublime-workspace
30+
31+
# IDE - VSCode
32+
.vscode/*
33+
!.vscode/settings.json
34+
!.vscode/tasks.json
35+
!.vscode/launch.json
36+
!.vscode/extensions.json
37+
38+
# dotenv environment variable files
39+
.env
40+
.env.development.local
41+
.env.test.local
42+
.env.production.local
43+
.env.local
44+
45+
# temp directory
46+
.temp
47+
.tmp
48+
49+
# Runtime data
50+
pids
51+
*.pid
52+
*.seed
53+
*.pid.lock
54+
55+
# Diagnostic reports (https://nodejs.org/api/report.html)
56+
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
57+
58+
test-results
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
@sentry:registry=http://127.0.0.1:4873
2+
@sentry-internal:registry=http://127.0.0.1:4873
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
## Assuming you already have installed docker desktop or orbstack etc. or any other docker software
2+
3+
### Enabling / authorising firebase emulator through docker
4+
5+
1. Run the docker
6+
7+
```bash
8+
pnpm docker
9+
```
10+
11+
2. In new tab, enter the docker container by simply running
12+
13+
```bash
14+
docker exec -it sentry-firebase bash
15+
```
16+
17+
3. Now inside docker container run
18+
19+
```bash
20+
firebase login
21+
```
22+
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+
```
32+
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
35+
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
43+
```
44+
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.
53+
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.**
56+
57+
### Scripts - helpers
58+
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
63+
64+
Use these scripts when testing and updating the environment settings on CLI
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"firestore": {
3+
"database": "(default)",
4+
"location": "nam5",
5+
"rules": "firestore.rules",
6+
"indexes": "firestore.indexes.json"
7+
},
8+
"emulators": {
9+
"firestore": {
10+
"port": 8080
11+
},
12+
"database": {
13+
"port": 9000
14+
},
15+
"ui": {
16+
"enabled": true
17+
},
18+
"singleProjectMode": true
19+
}
20+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"indexes": [],
3+
"fieldOverrides": []
4+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
rules_version='2'
2+
3+
service cloud.firestore {
4+
match /databases/{database}/documents {
5+
match /{document=**} {
6+
// This rule allows anyone with your database reference to view, edit,
7+
// and delete all data in your database. It is useful for getting
8+
// started, but it is configured to expire after 30 days because it
9+
// leaves your app open to attackers. At that time, all client
10+
// requests to your database will be denied.
11+
//
12+
// Make sure to write security rules for your app before that time, or
13+
// else all client requests to your database will be denied until you
14+
// update your rules.
15+
allow read, write: if request.time < timestamp.date(2025, 8, 17);
16+
}
17+
}
18+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"name": "node-firebase-e2e-test-app",
3+
"version": "0.0.1",
4+
"private": true,
5+
"scripts": {
6+
"build": "tsc",
7+
"dev": "tsc --build --watch",
8+
"proxy": "node start-event-proxy.mjs",
9+
"emulate": "firebase emulators:start &",
10+
"start": "node ./dist/app.js",
11+
"test": "playwright test",
12+
"clean": "npx rimraf node_modules pnpm-lock.yaml",
13+
"test:build": "pnpm install && pnpm build",
14+
"test:assert": "pnpm firebase emulators:exec 'pnpm test'"
15+
},
16+
"dependencies": {
17+
"@firebase/app": "^0.13.1",
18+
"@sentry/node": "latest || *",
19+
"@sentry/core": "latest || *",
20+
"@sentry/opentelemetry": "latest || *",
21+
"@types/node": "^18.19.1",
22+
"dotenv": "^16.4.5",
23+
"express": "^4.18.2",
24+
"firebase": "^12.0.0",
25+
"firebase-admin": "^12.0.0",
26+
"tsconfig-paths": "^4.2.0",
27+
"typescript": "4.9.5"
28+
},
29+
"devDependencies": {
30+
"@playwright/test": "~1.53.2",
31+
"@sentry-internal/test-utils": "link:../../../test-utils",
32+
"@types/express": "^4.17.13",
33+
"firebase-tools": "^12.0.0"
34+
},
35+
"volta": {
36+
"extends": "../../package.json"
37+
}
38+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { getPlaywrightConfig } from '@sentry-internal/test-utils';
2+
3+
const config = getPlaywrightConfig({
4+
startCommand: `pnpm start`,
5+
});
6+
7+
export default config;
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import * as Sentry from '@sentry/node';
2+
import './init';
3+
import express from 'express';
4+
import type { FirebaseOptions } from '@firebase/app';
5+
import { initializeApp } from 'firebase/app';
6+
import {
7+
addDoc,
8+
collection,
9+
connectFirestoreEmulator,
10+
deleteDoc,
11+
doc,
12+
getDocs,
13+
getFirestore,
14+
setDoc,
15+
} from 'firebase/firestore/lite';
16+
17+
const options: FirebaseOptions = {
18+
projectId: 'sentry-15d85',
19+
apiKey: 'sentry-fake-api-key',
20+
};
21+
22+
const app = initializeApp(options);
23+
24+
const db = getFirestore(app);
25+
connectFirestoreEmulator(db, '127.0.0.1', 8080);
26+
const citiesRef = collection(db, 'cities');
27+
28+
async function addCity(): Promise<void> {
29+
await addDoc(citiesRef, {
30+
name: 'San Francisco',
31+
});
32+
}
33+
34+
async function getCities(): Promise<unknown> {
35+
const citySnapshot = await getDocs(citiesRef);
36+
const cityList = citySnapshot.docs.map(doc => doc.data());
37+
return cityList;
38+
}
39+
40+
async function deleteCity(): Promise<void> {
41+
await deleteDoc(doc(citiesRef, 'SF'));
42+
}
43+
44+
async function setCity(): Promise<void> {
45+
await setDoc(doc(citiesRef, 'SF'), {
46+
name: 'San Francisco',
47+
state: 'CA',
48+
country: 'USA',
49+
capital: false,
50+
population: 860000,
51+
regions: ['west_coast', 'norcal'],
52+
});
53+
}
54+
55+
const expressApp = express();
56+
const port = 3030;
57+
58+
expressApp.get('/test', async function (req, res) {
59+
await Sentry.startSpan({ name: 'Test Transaction' }, async () => {
60+
await addCity();
61+
await setCity();
62+
await getCities();
63+
await deleteCity();
64+
});
65+
await Sentry.flush();
66+
res.send({ version: 'v1' });
67+
});
68+
69+
expressApp.listen(port, () => {
70+
console.log(`Example app listening on port ${port}`);
71+
});

0 commit comments

Comments
 (0)