Skip to content

Commit 9cb8eeb

Browse files
authored
chore(telemetry): allow sharing tags in a file and read it only when things change (#28953)
* chore(telemetry): allow sharing tags in a file and read it only when things change * Types
1 parent 7329d48 commit 9cb8eeb

File tree

2 files changed

+143
-0
lines changed

2 files changed

+143
-0
lines changed

packages/gatsby-telemetry/src/__tests__/telemetry.ts

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
jest.mock(`../event-storage`)
22
import { EventStorage } from "../event-storage"
33
import { AnalyticsTracker } from "../telemetry"
4+
import * as fs from "fs-extra"
5+
import * as os from "os"
6+
import * as path from "path"
7+
import uuidv4 from "uuid/v4"
48

59
let telemetry
610
beforeEach(() => {
@@ -57,4 +61,119 @@ describe(`Telemetry`, () => {
5761
)
5862
})
5963
})
64+
65+
describe(`allows reading tags from path`, () => {
66+
it(`getTagsFromPath should read the file and detect updates`, async () => {
67+
const t = new AnalyticsTracker({
68+
componentId: `component`,
69+
})
70+
71+
// Test it when env not set
72+
let res = t.getTagsFromPath()
73+
expect(res).toMatchObject({})
74+
expect(t.lastEnvTagsFromFileTime).toBe(0)
75+
76+
// create file and write initial data
77+
const filePath = path.join(fs.realpathSync(os.tmpdir()), uuidv4())
78+
console.log(filePath)
79+
process.env.GATSBY_TELEMETRY_METADATA_PATH = filePath
80+
81+
fs.writeFileSync(filePath, JSON.stringify({ componentId: `test` }))
82+
await new Promise(resolve => {
83+
setTimeout(resolve, 2000)
84+
})
85+
// get it and make sure we see it and the ts matches
86+
res = t.getTagsFromPath()
87+
expect(res).toMatchObject({ componentId: `test` })
88+
let stat = fs.statSync(filePath)
89+
expect(t.lastEnvTagsFromFileTime).toBe(stat.mtimeMs)
90+
91+
// Update the file
92+
fs.writeFileSync(filePath, JSON.stringify({ componentId: `test2` }))
93+
94+
await new Promise(resolve => {
95+
setTimeout(resolve, 2000)
96+
})
97+
stat = fs.statSync(filePath)
98+
// make sure we see the change
99+
res = t.getTagsFromPath()
100+
expect(t.lastEnvTagsFromFileTime).toBe(stat.mtimeMs)
101+
expect(res).toMatchObject({ componentId: `test2` })
102+
103+
// read it with out updating
104+
res = t.getTagsFromPath()
105+
expect(t.lastEnvTagsFromFileTime).toBe(stat.mtimeMs)
106+
expect(res).toMatchObject({ componentId: `test2` })
107+
fs.unlinkSync(filePath)
108+
109+
const filePath2 = path.join(fs.realpathSync(os.tmpdir()), uuidv4())
110+
process.env.GATSBY_TELEMETRY_METADATA_PATH = filePath2
111+
res = t.getTagsFromPath()
112+
expect(t.lastEnvTagsFromFileTime).toBe(stat.mtimeMs)
113+
expect(res).toMatchObject({})
114+
}, 10000)
115+
})
116+
117+
it(`getTagsFromPath is used for buildEvent`, async () => {
118+
const t = new AnalyticsTracker({
119+
componentId: `component`,
120+
})
121+
t.buildAndStoreEvent(`demo`, {})
122+
expect(
123+
(EventStorage as jest.Mock).mock.instances[1].addEvent
124+
).toHaveBeenCalledWith(
125+
expect.objectContaining({
126+
eventType: `demo`,
127+
componentId: `component`,
128+
})
129+
)
130+
const filePath = path.join(fs.realpathSync(os.tmpdir()), uuidv4())
131+
process.env.GATSBY_TELEMETRY_METADATA_PATH = filePath
132+
fs.writeFileSync(filePath, JSON.stringify({ componentId: `test` }))
133+
await new Promise(resolve => {
134+
setTimeout(resolve, 2000)
135+
})
136+
const stat = fs.statSync(filePath)
137+
t.buildAndStoreEvent(`demo2`, {})
138+
139+
expect(t.lastEnvTagsFromFileTime).toBe(stat.mtimeMs)
140+
expect(
141+
(EventStorage as jest.Mock).mock.instances[1].addEvent
142+
).toHaveBeenCalledWith(
143+
expect.objectContaining({
144+
eventType: `demo2`,
145+
componentId: `test`,
146+
})
147+
)
148+
149+
t.buildAndStoreEvent(`demo3`, {})
150+
expect(
151+
(EventStorage as jest.Mock).mock.instances[1].addEvent
152+
).toHaveBeenCalledWith(
153+
expect.objectContaining({
154+
eventType: `demo3`,
155+
componentId: `test`,
156+
})
157+
)
158+
159+
expect(t.lastEnvTagsFromFileTime).toBe(stat.mtimeMs)
160+
161+
fs.writeFileSync(filePath, JSON.stringify({ componentId: `4` }))
162+
await new Promise(resolve => {
163+
setTimeout(resolve, 2000)
164+
})
165+
const stat2 = fs.statSync(filePath)
166+
167+
t.buildAndStoreEvent(`demo4`, {})
168+
expect(t.lastEnvTagsFromFileTime).toBe(stat2.mtimeMs)
169+
expect(
170+
(EventStorage as jest.Mock).mock.instances[1].addEvent
171+
).toHaveBeenCalledWith(
172+
expect.objectContaining({
173+
eventType: `demo4`,
174+
componentId: `4`,
175+
})
176+
)
177+
fs.unlinkSync(filePath)
178+
}, 10000)
60179
})

packages/gatsby-telemetry/src/telemetry.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import uuidv4 from "uuid/v4"
2+
import * as fs from "fs-extra"
23
import os from "os"
34
import {
45
isCI,
@@ -136,6 +137,8 @@ export class AnalyticsTracker {
136137
features = new Set<string>()
137138
machineId: string
138139
siteHash?: string = createContentDigest(process.cwd())
140+
lastEnvTagsFromFileTime = 0
141+
lastEnvTagsFromFileValue: ITelemetryTagsPayload = {}
139142

140143
constructor({
141144
componentId,
@@ -361,6 +364,7 @@ export class AnalyticsTracker {
361364
dbEngine,
362365
features: Array.from(this.features),
363366
...this.getRepositoryId(),
367+
...this.getTagsFromPath(),
364368
}
365369
this.store.addEvent(event)
366370
if (this.isFinalEvent(eventType)) {
@@ -370,6 +374,26 @@ export class AnalyticsTracker {
370374
}
371375
}
372376

377+
getTagsFromPath(): ITelemetryTagsPayload {
378+
const path = process.env.GATSBY_TELEMETRY_METADATA_PATH
379+
380+
if (!path) {
381+
return {}
382+
}
383+
try {
384+
const stat = fs.statSync(path)
385+
if (this.lastEnvTagsFromFileTime < stat.mtimeMs) {
386+
this.lastEnvTagsFromFileTime = stat.mtimeMs
387+
const data = fs.readFileSync(path, `utf8`)
388+
this.lastEnvTagsFromFileValue = JSON.parse(data)
389+
}
390+
} catch (e) {
391+
// nop
392+
return {}
393+
}
394+
return this.lastEnvTagsFromFileValue
395+
}
396+
373397
getIsTTY(): boolean {
374398
return Boolean(process.stdout?.isTTY)
375399
}

0 commit comments

Comments
 (0)