Skip to content

Commit ffcf2f3

Browse files
authored
refactor: bring our own telemtry
see FilOzone/synapse-sdk#363
1 parent 5fcb542 commit ffcf2f3

File tree

19 files changed

+100
-123
lines changed

19 files changed

+100
-123
lines changed

README.md

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -105,23 +105,17 @@ The [Synapse SDK](https://synapse.filecoin.services/) is the main library, as it
105105

106106
The affordances were [discussed more above](#affordances). All affordances use the same core library, ensuring consistent behavior and making it easy to add new interfaces in the future.
107107

108-
## Telemetry
108+
## CLI Telemetry
109109

110-
Filecoin Pain collects telemetry. A few things:
110+
Filecoin Pin's CLI collects telemetry. A few things:
111111
* Telemetry always [has a way to be disabled](#how-to-disable-telemetry).
112112
* We don't collect Personal identifiable information (PII).
113113
* With our [end user affordance](#affordances) we expect to make telemetry on by default, requiring a consumer/user to opt out. We are defaulting as "enabled" to help make sure we have a good pulse on the user experience and can address issues correctly.
114-
* In this [pre-v1 season](https://github.com/filecoin-project/filecoin-pin/issues/187), we are particularly focused on helping maintainers validate functionality and iron out problems throughout the whole Filecoin Onchain Cloud stack that `filecoin-pin` relies on. We're piggy-backing on the underlying telemetry setup/system of Synapse, which uses sentry.io. The telemetry we get from synapse-sdk is more invasive than we'd do if just setting it up for [Filecoin Pin affordances](#affordances), but this was the most resource efficient way to be able to get a pulse on what errors are happening where in the stack.
115-
* Learn more at the Synapse telemetry docs ([docs site](https://synapse.filecoin.services/guides/telemetry/), [github](https://github.com/FilOzone/synapse-sdk/blob/master/docs/src/content/docs/guides/telemetry.md)).
114+
* In this [pre-v1 season](https://github.com/filecoin-project/filecoin-pin/issues/187), we are particularly focused on helping maintainers validate functionality and iron out problems throughout the whole Filecoin Onchain Cloud stack that `filecoin-pin` relies on.
116115

117-
### How to disable telemetry
118-
Telemetry can be disabled in JS with:
116+
### How to disable CLI telemetry
119117

120-
```typescript
121-
const synapse = await initializeSynapse({ ...synapseConfig, telemetry: { sentryInitOptions: { enabled: false } } }, logger)
122-
```
123-
124-
If using a different affordance like the CLI or example GitHub Action, then the following telemetry can be disabled by environment variable. Because filecoin-pin telemetry is tied to synapse's telemetry currently, see the Synapse telemetry docs ([docs site](https://synapse.filecoin.services/guides/telemetry/#how-to-disable-telemetry), [github](https://github.com/FilOzone/synapse-sdk/blob/master/docs/src/content/docs/guides/telemetry.md#how-to-disable-telemetry)) for how to do this.
118+
Set the environment variable `FILECOIN_PIN_TELEMETRY_DISABLED=true`.
125119

126120
## Quick Start
127121

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@
117117
"@filoz/synapse-sdk": "^0.36.1",
118118
"@helia/unixfs": "^7.0.0",
119119
"@ipld/car": "^5.4.2",
120+
"@sentry/node": "^10.35.0",
120121
"commander": "^14.0.1",
121122
"ethers": "^6.15.0",
122123
"fastify": "^5.6.0",

src/add/add.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import { readFile, stat } from 'node:fs/promises'
99
import pc from 'picocolors'
1010
import pino from 'pino'
1111
import { warnAboutCDNPricingLimitations } from '../common/cdn-warning.js'
12-
import { TELEMETRY_CLI_APP_NAME } from '../common/constants.js'
1312
import { displayUploadResults, performAutoFunding, performUpload, validatePaymentSetup } from '../common/upload-flow.js'
1413
import { normalizeMetadataConfig } from '../core/metadata/index.js'
1514
import {
@@ -45,7 +44,10 @@ async function validatePath(
4544
if (stats.isDirectory()) {
4645
// Check if bare flag is used with directory
4746
if (options.bare) {
48-
return { exists: false, error: `--bare flag is not supported for directories` }
47+
return {
48+
exists: false,
49+
error: `--bare flag is not supported for directories`,
50+
}
4951
}
5052
return { exists: true, stats, isDirectory: true }
5153
}
@@ -57,7 +59,10 @@ async function validatePath(
5759
return { exists: false, error: `Path not found: ${path}` }
5860
}
5961
// Other errors like permission denied, etc.
60-
return { exists: false, error: `Cannot access path: ${path} (${error?.message || 'unknown error'})` }
62+
return {
63+
exists: false,
64+
error: `Cannot access path: ${path} (${error?.message || 'unknown error'})`,
65+
}
6166
}
6267
}
6368

@@ -122,18 +127,17 @@ export async function runAdd(options: AddOptions): Promise<AddResult> {
122127
if (withCDN) config.withCDN = true
123128

124129
// Initialize just the Synapse SDK
125-
const synapse = await initializeSynapse(
126-
{ ...config, telemetry: { sentrySetTags: { appName: TELEMETRY_CLI_APP_NAME } } },
127-
logger
128-
)
130+
const synapse = await initializeSynapse(config, logger)
129131
const network = synapse.getNetwork()
130132

131133
spinner.stop(`${pc.green('✓')} Connected to ${pc.bold(network)}`)
132134

133135
// Check payment setup (may configure permissions if needed)
134136
// Actual CAR size will be checked later
135137
spinner.start('Checking payment setup...')
136-
await validatePaymentSetup(synapse, 0, spinner, { suppressSuggestions: true })
138+
await validatePaymentSetup(synapse, 0, spinner, {
139+
suppressSuggestions: true,
140+
})
137141

138142
// Create CAR from file or directory
139143
const packingMsg = isDirectory

src/cli.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#!/usr/bin/env node
2+
import './instrument.js'
23
import { Command } from 'commander'
34
import pc from 'picocolors'
45

src/common/constants.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,3 @@
22
* Minimum runway in days to ensure WarmStorage can cover costs. Used when `--auto-fund` is passed to import or add commands
33
*/
44
export const MIN_RUNWAY_DAYS = 30
5-
6-
export const TELEMETRY_CLI_APP_NAME = 'filecoinPinCli'

src/core/synapse/index.ts

Lines changed: 27 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,11 @@ import {
88
type StorageServiceOptions,
99
Synapse,
1010
type SynapseOptions,
11-
type TelemetryConfig,
1211
} from '@filoz/synapse-sdk'
1312
import { type Provider as EthersProvider, JsonRpcProvider, type Signer, Wallet, WebSocketProvider } from 'ethers'
1413
import type { Logger } from 'pino'
1514
import { ADDRESS_ONLY_SIGNER_SYMBOL, AddressOnlySigner } from './address-only-signer.js'
1615
import { DEFAULT_DATA_SET_METADATA, DEFAULT_STORAGE_CONTEXT_CONFIG } from './constants.js'
17-
import { getTelemetryConfig } from './telemetry-config.js'
1816

1917
export * from './constants.js'
2018

@@ -46,7 +44,7 @@ export interface Config {
4644
/**
4745
* Common options for all Synapse configurations
4846
*/
49-
interface BaseSynapseConfig extends Omit<SynapseOptions, 'withCDN' | 'warmStorageAddress' | 'telemetry'> {
47+
interface BaseSynapseConfig extends Omit<SynapseOptions, 'withCDN' | 'warmStorageAddress'> {
5048
/** RPC endpoint for the target Filecoin network. Defaults to calibration. */
5149
rpcUrl?: string | undefined
5250
/** Optional override for WarmStorage contract address */
@@ -56,20 +54,6 @@ interface BaseSynapseConfig extends Omit<SynapseOptions, 'withCDN' | 'warmStorag
5654
withCDN?: boolean | undefined
5755
/** Default metadata to apply when creating or reusing datasets */
5856
dataSetMetadata?: Record<string, string>
59-
/**
60-
* Telemetry configuration.
61-
* Defaults to enabled unless explicitly disabled.
62-
* @example
63-
* {
64-
* sentryInitOptions: {
65-
* enabled: false, // if want to disable telemetry.
66-
* },
67-
* sentrySetTags: {
68-
* appName: "${your-app-name}",
69-
* },
70-
* }
71-
*/
72-
telemetry?: TelemetryConfig
7357
}
7458

7559
/**
@@ -353,7 +337,11 @@ async function setupSessionKey(synapse: Synapse, sessionWallet: Wallet, logger:
353337
}
354338

355339
logger.info(
356-
{ event: 'synapse.session_key.verified', createExpiry: createDataSetExpiry, addExpiry: addPiecesExpiry },
340+
{
341+
event: 'synapse.session_key.verified',
342+
createExpiry: createDataSetExpiry,
343+
addExpiry: addPiecesExpiry,
344+
},
357345
'Session key verified'
358346
)
359347

@@ -374,7 +362,7 @@ async function setupSessionKey(synapse: Synapse, sessionWallet: Wallet, logger:
374362
* @returns Initialized Synapse instance
375363
*/
376364
export async function initializeSynapse(config: Partial<SynapseSetupConfig>, logger: Logger): Promise<Synapse> {
377-
const { withCDN, warmStorageAddress, telemetry, ...restConfig } = config
365+
const { withCDN, warmStorageAddress, ...restConfig } = config
378366
try {
379367
const authMode = validateAuthConfig(config)
380368

@@ -399,7 +387,6 @@ export async function initializeSynapse(config: Partial<SynapseSetupConfig>, log
399387
if (warmStorageAddress) {
400388
synapseOptions.warmStorageAddress = warmStorageAddress
401389
}
402-
synapseOptions.telemetry = getTelemetryConfig(telemetry)
403390

404391
let synapse: Synapse
405392

@@ -445,7 +432,10 @@ export async function initializeSynapse(config: Partial<SynapseSetupConfig>, log
445432
throw new Error('Internal error: signer mode but config type mismatch')
446433
}
447434

448-
synapse = await Synapse.create({ ...synapseOptions, signer: config.signer })
435+
synapse = await Synapse.create({
436+
...synapseOptions,
437+
signer: config.signer,
438+
})
449439
activeProvider = synapse.getProvider()
450440
setAuthMode(synapse, 'signer')
451441
} else {
@@ -454,7 +444,10 @@ export async function initializeSynapse(config: Partial<SynapseSetupConfig>, log
454444
throw new Error('Internal error: private key mode but config type mismatch')
455445
}
456446

457-
synapse = await Synapse.create({ ...synapseOptions, privateKey: config.privateKey })
447+
synapse = await Synapse.create({
448+
...synapseOptions,
449+
privateKey: config.privateKey,
450+
})
458451
activeProvider = synapse.getProvider()
459452
setAuthMode(synapse, 'standard')
460453
}
@@ -522,7 +515,10 @@ export async function createStorageContext(
522515
if (options?.dataset?.useExisting != null) {
523516
sdkOptions.dataSetId = options.dataset.useExisting
524517
logger?.info?.(
525-
{ event: 'synapse.storage.dataset.existing', dataSetId: options.dataset.useExisting },
518+
{
519+
event: 'synapse.storage.dataset.existing',
520+
dataSetId: options.dataset.useExisting,
521+
},
526522
'Connecting to existing dataset'
527523
)
528524
} else if (options?.dataset?.createNew === true) {
@@ -595,13 +591,19 @@ export async function createStorageContext(
595591
if (options?.providerAddress) {
596592
sdkOptions.providerAddress = options.providerAddress
597593
logger?.info?.(
598-
{ event: 'synapse.storage.provider_override', providerAddress: options.providerAddress },
594+
{
595+
event: 'synapse.storage.provider_override',
596+
providerAddress: options.providerAddress,
597+
},
599598
'Overriding provider by address'
600599
)
601600
} else if (options?.providerId != null && Number.isFinite(options.providerId)) {
602601
sdkOptions.providerId = options.providerId
603602
logger?.info?.(
604-
{ event: 'synapse.storage.provider_override', providerId: options.providerId },
603+
{
604+
event: 'synapse.storage.provider_override',
605+
providerId: options.providerId,
606+
},
605607
'Overriding provider by ID'
606608
)
607609
}
@@ -761,11 +763,6 @@ export async function cleanupProvider(provider: any): Promise<void> {
761763
* and allow the process to terminate
762764
*/
763765
export async function cleanupSynapseService(): Promise<void> {
764-
// Close telemetry to flush pending events and shutdown cleanly
765-
if (synapseInstance) {
766-
await synapseInstance.telemetry?.sentry?.close()
767-
}
768-
769766
if (activeProvider) {
770767
await cleanupProvider(activeProvider)
771768
}

src/core/synapse/telemetry-config.ts

Lines changed: 0 additions & 18 deletions
This file was deleted.

src/filecoin-pinning-server.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,6 @@ export async function createFilecoinPinningServer(
3838
{
3939
...config,
4040
privateKey: config.privateKey,
41-
telemetry: {
42-
sentrySetTags: {
43-
appName: 'filecoinPinIPFSPinningServer',
44-
},
45-
},
4641
},
4742
logger,
4843
providerOptions

src/import/import.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import { CID } from 'multiformats/cid'
1212
import pc from 'picocolors'
1313
import pino from 'pino'
1414
import { warnAboutCDNPricingLimitations } from '../common/cdn-warning.js'
15-
import { TELEMETRY_CLI_APP_NAME } from '../common/constants.js'
1615
import { displayUploadResults, performAutoFunding, performUpload, validatePaymentSetup } from '../common/upload-flow.js'
1716
import { normalizeMetadataConfig } from '../core/metadata/index.js'
1817
import {
@@ -57,7 +56,11 @@ async function validateCarFile(filePath: string): Promise<CID[]> {
5756
* Resolve the root CID from CAR file roots
5857
* Handles multiple cases: no roots, single root, multiple roots
5958
*/
60-
function resolveRootCID(roots: CID[]): { cid: CID; cidString: string; message?: string } {
59+
function resolveRootCID(roots: CID[]): {
60+
cid: CID
61+
cidString: string
62+
message?: string
63+
} {
6164
if (roots.length === 0) {
6265
// No roots - use zero CID
6366
return {
@@ -115,7 +118,10 @@ async function validateFilePath(filePath: string): Promise<{ exists: boolean; st
115118
return { exists: false, error: `File not found: ${filePath}` }
116119
}
117120
// Other errors like permission denied, etc.
118-
return { exists: false, error: `Cannot access file: ${filePath} (${error?.message || 'unknown error'})` }
121+
return {
122+
exists: false,
123+
error: `Cannot access file: ${filePath} (${error?.message || 'unknown error'})`,
124+
}
119125
}
120126
}
121127

@@ -192,10 +198,7 @@ export async function runCarImport(options: ImportOptions): Promise<ImportResult
192198
if (withCDN) config.withCDN = true
193199

194200
// Initialize just the Synapse SDK
195-
const synapse = await initializeSynapse(
196-
{ ...config, telemetry: { sentrySetTags: { appName: TELEMETRY_CLI_APP_NAME } } },
197-
logger
198-
)
201+
const synapse = await initializeSynapse(config, logger)
199202
const network = synapse.getNetwork()
200203

201204
spinner.stop(`${pc.green('✓')} Connected to ${pc.bold(network)}`)

src/instrument.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import Sentry from '@sentry/node'
2+
import { name as packageName, version as packageVersion } from './core/utils/version.js'
3+
4+
// Ensure to call this before requiring any other modules!
5+
Sentry.init({
6+
dsn: 'https://9TMHhmfsi93WgHaMSXoQ2qhQ@s1685337.us-east-9.betterstackdata.com/1685337',
7+
// Setting this option to false will prevent the SDK from sending default PII data to Sentry.
8+
// For example, automatic IP address collection on events
9+
sendDefaultPii: false,
10+
// Enable tracing/performance monitoring
11+
tracesSampleRate: 1.0, // Capture 100% of transactions for development (adjust in production)
12+
enabled: process.env.FILECOIN_PIN_TELEMETRY_DISABLED !== 'true',
13+
})
14+
15+
Sentry.setTags({
16+
filecoinPinVersion: `${packageName}@v${packageVersion}`,
17+
})

0 commit comments

Comments
 (0)