@@ -7,6 +7,7 @@ import { Logger } from "./sentry/logger";
77import { promisify } from "util" ;
88import { Hub , NodeClient } from "@sentry/node" ;
99import SentryCli from "@sentry/cli" ;
10+ import { dynamicSamplingContextToSentryBaggageHeader } from "@sentry/utils" ;
1011
1112interface RewriteSourcesHook {
1213 ( source : string , map : any ) : string ;
@@ -48,14 +49,18 @@ export function createDebugIdUploadFunction({
4849 deleteFilesAfterUpload,
4950} : DebugIdUploadPluginOptions ) {
5051 return async ( buildArtifactPaths : string [ ] ) => {
51- let folderToCleanUp : string | undefined ;
52+ const artifactBundleUploadTransaction = sentryHub . startTransaction ( {
53+ name : "debug-id-sourcemap-upload" ,
54+ } ) ;
5255
53- const cliInstance = new SentryCli ( null , sentryCliOptions ) ;
56+ let folderToCleanUp : string | undefined ;
5457
5558 try {
59+ const mkdtempSpan = artifactBundleUploadTransaction . startChild ( { description : "mkdtemp" } ) ;
5660 const tmpUploadFolder = await fs . promises . mkdtemp (
5761 path . join ( os . tmpdir ( ) , "sentry-bundler-plugin-upload-" )
5862 ) ;
63+ mkdtempSpan . finish ( ) ;
5964
6065 folderToCleanUp = tmpUploadFolder ;
6166
@@ -69,13 +74,15 @@ export function createDebugIdUploadFunction({
6974 globAssets = buildArtifactPaths ;
7075 }
7176
72- const debugIdChunkFilePaths = (
73- await glob ( globAssets , {
74- absolute : true ,
75- nodir : true ,
76- ignore : ignore ,
77- } )
78- ) . filter (
77+ const globSpan = artifactBundleUploadTransaction . startChild ( { description : "glob" } ) ;
78+ const globResult = await glob ( globAssets , {
79+ absolute : true ,
80+ nodir : true ,
81+ ignore : ignore ,
82+ } ) ;
83+ globSpan . finish ( ) ;
84+
85+ const debugIdChunkFilePaths = globResult . filter (
7986 ( debugIdChunkFilePath ) =>
8087 debugIdChunkFilePath . endsWith ( ".js" ) ||
8188 debugIdChunkFilePath . endsWith ( ".mjs" ) ||
@@ -91,6 +98,9 @@ export function createDebugIdUploadFunction({
9198 "Didn't find any matching sources for debug ID upload. Please check the `sourcemaps.assets` option."
9299 ) ;
93100 } else {
101+ const prepareSpan = artifactBundleUploadTransaction . startChild ( {
102+ description : "prepare-bundles" ,
103+ } ) ;
94104 await Promise . all (
95105 debugIdChunkFilePaths . map ( async ( chunkFilePath , chunkIndex ) : Promise < void > => {
96106 await prepareBundleForDebugIdUpload (
@@ -102,6 +112,33 @@ export function createDebugIdUploadFunction({
102112 ) ;
103113 } )
104114 ) ;
115+ prepareSpan . finish ( ) ;
116+
117+ const files = await fs . promises . readdir ( tmpUploadFolder ) ;
118+ const stats = files . map ( ( file ) => fs . promises . stat ( path . join ( tmpUploadFolder , file ) ) ) ;
119+ const uploadSize = ( await Promise . all ( stats ) ) . reduce (
120+ ( accumulator , { size } ) => accumulator + size ,
121+ 0
122+ ) ;
123+
124+ artifactBundleUploadTransaction . setMeasurement ( "files" , files . length , "none" ) ;
125+ artifactBundleUploadTransaction . setMeasurement ( "upload_size" , uploadSize , "byte" ) ;
126+
127+ const uploadSpan = artifactBundleUploadTransaction . startChild ( {
128+ description : "upload" ,
129+ } ) ;
130+
131+ const cliInstance = new SentryCli ( null , {
132+ ...sentryCliOptions ,
133+ headers : {
134+ "sentry-trace" : uploadSpan . toTraceparent ( ) ,
135+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
136+ baggage : dynamicSamplingContextToSentryBaggageHeader (
137+ artifactBundleUploadTransaction . getDynamicSamplingContext ( )
138+ ) ! ,
139+ ...sentryCliOptions . headers ,
140+ } ,
141+ } ) ;
105142
106143 await cliInstance . releases . uploadSourceMaps (
107144 releaseName ?? "undefined" , // unfortunetly this needs a value for now but it will not matter since debug IDs overpower releases anyhow
@@ -116,32 +153,50 @@ export function createDebugIdUploadFunction({
116153 useArtifactBundle : true ,
117154 }
118155 ) ;
156+
157+ uploadSpan . finish ( ) ;
119158 }
120159
121160 if ( deleteFilesAfterUpload ) {
161+ const deleteGlobSpan = artifactBundleUploadTransaction . startChild ( {
162+ description : "delete-glob" ,
163+ } ) ;
122164 const filePathsToDelete = await glob ( deleteFilesAfterUpload , {
123165 absolute : true ,
124166 nodir : true ,
125167 } ) ;
168+ deleteGlobSpan . finish ( ) ;
126169
127170 filePathsToDelete . forEach ( ( filePathToDelete ) => {
128171 logger . debug ( `Deleting asset after upload: ${ filePathToDelete } ` ) ;
129172 } ) ;
130173
174+ const deleteSpan = artifactBundleUploadTransaction . startChild ( {
175+ description : "delete-files-after-upload" ,
176+ } ) ;
131177 await Promise . all (
132178 filePathsToDelete . map ( ( filePathToDelete ) =>
133179 fs . promises . rm ( filePathToDelete , { force : true } )
134180 )
135181 ) ;
182+ deleteSpan . finish ( ) ;
136183 }
137184 } catch ( e ) {
138- sentryHub . captureException ( 'Error in "debugIdUploadPlugin" writeBundle hook' ) ;
139- await sentryClient . flush ( ) ;
185+ sentryHub . withScope ( ( scope ) => {
186+ scope . setSpan ( artifactBundleUploadTransaction ) ;
187+ sentryHub . captureException ( 'Error in "debugIdUploadPlugin" writeBundle hook' ) ;
188+ } ) ;
140189 handleRecoverableError ( e ) ;
141190 } finally {
142191 if ( folderToCleanUp ) {
192+ const cleanupSpan = artifactBundleUploadTransaction . startChild ( {
193+ description : "cleanup" ,
194+ } ) ;
143195 void fs . promises . rm ( folderToCleanUp , { recursive : true , force : true } ) ;
196+ cleanupSpan . finish ( ) ;
144197 }
198+ artifactBundleUploadTransaction . finish ( ) ;
199+ await sentryClient . flush ( ) ;
145200 }
146201 } ;
147202}
0 commit comments