@@ -87,12 +87,18 @@ function isGeneratedLocation(
8787 * (`column << 32 | line`) — the encoding the Datadog deobfuscation backend
8888 * decodes (the same one the Chrome profile intake uses). Required to
8989 * deobfuscate single-line (bundled/minified) frames, where the column is the
90- * only discriminator between functions.
91- *
92- * The enum leaves room for a future `'emit'` mode that would populate a real
93- * pprof `Line.column` field once the backend consumes it.
90+ * only discriminator between functions. Only frames whose source map was
91+ * declared but missing locally are packed.
92+ * - `'emit'`: like `'pack'`, but records the column in the dedicated pprof
93+ * `Line.column` field instead of packing it into the line field, so the line
94+ * field stays standards-compliant and the two concerns are cleanly separated.
95+ * Scoped to the same frames as `'pack'` — only those whose source map was
96+ * declared but missing locally, i.e. the frames bound for server-side
97+ * unminification. The Datadog backend performs the `column << 32 | line`
98+ * packing itself (for Node.js profiles) when it consumes the column field.
99+ * Requires pprof-format >= 2.3.0, the version that added `Line.column`.
94100 */
95- export type ColumnNumbers = 'drop' | 'pack' ;
101+ export type ColumnNumbers = 'drop' | 'pack' | 'emit' ;
96102
97103export const DEFAULT_COLUMN_NUMBERS : ColumnNumbers = 'drop' ;
98104
@@ -158,6 +164,7 @@ function serialize<T extends ProfileNode>(
158164 const functionIdMap = new Map < string , number > ( ) ;
159165 const locationIdMap = new Map < string , number > ( ) ;
160166 const packColumns = columnNumbers === 'pack' ;
167+ const emitColumns = columnNumbers === 'emit' ;
161168
162169 let hasMissingMapFiles = false ;
163170
@@ -230,15 +237,23 @@ function serialize<T extends ProfileNode>(
230237 }
231238
232239 function getLine ( loc : SourceLocation , scriptId ?: number ) : Line {
233- // Only pack the column for frames whose source map was declared but missing
234- // locally — i.e. exactly the frames that will be sent for server-side
235- // unminification (the same condition that sets dd:has-missing-map-files).
236- // Locally-resolved frames keep their plain line, so packed values never
237- // reach profiles that skip server-side unminification.
238- const packColumn = packColumns && loc . missingMapFile === true ;
240+ // Both 'pack' and 'emit' carry the column only for frames whose source map
241+ // was declared but missing locally — i.e. exactly the frames bound for
242+ // server-side unminification (the same condition that sets
243+ // dd:has-missing-map-files). Locally-resolved frames keep a plain line and
244+ // no column, so column data never reaches profiles that skip server-side
245+ // unminification.
246+ const carryColumn = loc . missingMapFile === true ;
239247 return new Line ( {
240248 functionId : getFunction ( loc , scriptId ) . id ,
241- line : packColumn ? packLineAndColumn ( loc . line , loc . column ) : loc . line ,
249+ // 'pack' encodes the column into the high 32 bits of the line field.
250+ line :
251+ packColumns && carryColumn
252+ ? packLineAndColumn ( loc . line , loc . column )
253+ : loc . line ,
254+ // 'emit' records the column in the dedicated pprof Line.column field
255+ // instead; the backend does the line/column packing itself.
256+ column : emitColumns && carryColumn ? loc . column : undefined ,
242257 } ) ;
243258 }
244259
0 commit comments