Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Capture more information when running cells #15559

Merged
merged 1 commit into from
Apr 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/gdpr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,14 @@
"startKernel": {"classification":"SystemMetaData","purpose":"FeatureInsight","comment":"% Time spent in starting the kernel.","owner":"donjayamanne","isMeasurement":true},
"startupCode": {"classification":"SystemMetaData","purpose":"FeatureInsight","comment":"% Time spent in executing startup code.","owner":"donjayamanne","isMeasurement":true},
"updateConnection": {"classification":"SystemMetaData","purpose":"FeatureInsight","comment":"% Time spent in updating the kernel connection.","owner":"donjayamanne","isMeasurement":true},
"codeCellCount": {"classification":"SystemMetaData","purpose":"FeatureInsight","comment":"Number of code cells in the notebook.","owner":"donjayamanne","isMeasurement":true},
"mdCellCount": {"classification":"SystemMetaData","purpose":"FeatureInsight","comment":"Number of md cells in the notebook.","owner":"donjayamanne","isMeasurement":true},
"codeCellCharLength": {"classification":"SystemMetaData","purpose":"FeatureInsight","comment":"Total char length of all text in all code cells.","owner":"donjayamanne","isMeasurement":true},
"mdCellCharLength": {"classification":"SystemMetaData","purpose":"FeatureInsight","comment":"Total char length of all text in all md cells.","owner":"donjayamanne","isMeasurement":true},
"outputCount": {"classification":"SystemMetaData","purpose":"FeatureInsight","comment":"Total number of outputs in all cells.","owner":"donjayamanne","isMeasurement":true},
"outputsByteSize": {"classification":"SystemMetaData","purpose":"FeatureInsight","comment":"Total bytes of all outputs in all cells.","owner":"donjayamanne","isMeasurement":true},
"attachmentCount": {"classification":"SystemMetaData","purpose":"FeatureInsight","comment":"Total number of attachments","owner":"donjayamanne","isMeasurement":true},
"attachmentCharLength": {"classification":"SystemMetaData","purpose":"FeatureInsight","comment":"Total number of chars in the attachment (generally these are base64 encoded strings).","owner":"donjayamanne","isMeasurement":true},
"${include}": [
"${F1}"

Expand Down
92 changes: 89 additions & 3 deletions src/kernels/telemetry/notebookTelemetry.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { workspace, type NotebookDocument, type Uri } from 'vscode';
import { NotebookCellKind, workspace, type NotebookDocument, type Uri } from 'vscode';
import { DisposableStore } from '../../platform/common/utils/lifecycle';
import { isUri } from '../../platform/common/utils/misc';
import { once } from '../../platform/common/utils/functional';
import { sendKernelTelemetryEvent } from './sendKernelTelemetryEvent';
import { Telemetry } from '../../platform/common/constants';
import type { Environment } from '@vscode/python-extension';
import { getCellMetadata } from '../../platform/common/utils';
import { traceWarning } from '../../platform/logging';

/* eslint-disable @typescript-eslint/no-use-before-define */

Expand Down Expand Up @@ -245,7 +247,40 @@ type SpawnSummary = {
envVars: number;
interruptHandle: number;
};

type NotebookSummary = {
/**
* Number of code cells in the notebook.
*/
codeCellCount: number;
/**
* Number of md cells in the notebook.
*/
mdCellCount: number;
/**
* Total char length of all text in all code cells.
*/
codeCellCharLength: number;
/**
* Total char length of all text in all md cells.
*/
mdCellCharLength: number;
/**
* Total number of outputs in all cells.
*/
outputCount: number;
/**
* Total bytes of all outputs in all cells.
*/
outputsByteSize: number;
/**
* Total number of attachments
*/
attachmentCount: number;
/**
* Total number of chars in the attachment (generally these are base64 encoded strings).
*/
attachmentCharLength: number;
};
const sendTelemetry = once(function (
notebook: NotebookDocument,
info: {
Expand Down Expand Up @@ -436,15 +471,66 @@ const sendTelemetry = once(function (
const duration = measures.spawnCompletedAfter - measures.spawnStartedAfter;
computeSummary(spawnSummary, spawnSummaryParts, duration, measures.openedAfter);
}
const notebookSummary = computeNotebookSummary(notebook);
const allMeasures: BriefSummary & StartupSummary & PostKernelStartupSummary & SpawnSummary = {
...briefSummary,
...startupSummary,
...postKernelStartSummary,
...spawnSummary
...spawnSummary,
...notebookSummary
};
sendKernelTelemetryEvent(notebook.uri, Telemetry.NotebookFirstStartBreakDown, allMeasures, info);
});

function computeNotebookSummary(notebook: NotebookDocument) {
const notebookSummary: NotebookSummary = {
attachmentCharLength: 0,
attachmentCount: 0,
codeCellCharLength: 0,
codeCellCount: 0,
mdCellCharLength: 0,
mdCellCount: 0,
outputCount: 0,
outputsByteSize: 0
};

notebook.getCells().forEach((cell) => {
const lastChar = cell.document.lineAt(cell.document.lineCount - 1).range.end;
const length = cell.document.offsetAt(lastChar);
if (cell.kind === NotebookCellKind.Markup) {
notebookSummary.mdCellCount += 1;
notebookSummary.mdCellCharLength += length;
try {
const metadata = getCellMetadata(cell);
const attachments = (metadata.attachments || {}) as unknown as Record<string, string>;
Object.keys(attachments).forEach((key) => {
notebookSummary.attachmentCount += 1;
const attachment = attachments[key] as unknown as Record<string, string>;
if (typeof attachment === 'object') {
Object.keys(attachment).forEach((mime) => {
const value = attachment[mime];
if (value && typeof value === 'string') {
notebookSummary.attachmentCharLength += value.length;
}
});
}
});
} catch (error) {
traceWarning(`Error parsing attachments in cell metadata`, error);
}
} else {
notebookSummary.codeCellCount += 1;
notebookSummary.codeCellCharLength += length;
notebookSummary.outputCount += cell.outputs.length;
notebookSummary.outputsByteSize += cell.outputs.reduce(
(acc, output) => acc + output.items.reduce((itemTotal, item) => itemTotal + item.data.byteLength, 0),
0
);
}
});

return notebookSummary;
}
const sendTelemetryForFirstAutoSelectedKernel = once(function (
notebook: NotebookDocument,
info: {
Expand Down
4 changes: 2 additions & 2 deletions src/platform/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -457,14 +457,14 @@ type JupyterCellMetadata = Pick<nbformat.IRawCell, 'id' | 'metadata' | 'attachme

export function getCellMetadata(cell: NotebookCell): JupyterCellMetadata {
if (useCustomMetadata()) {
const metadata: JupyterCellMetadata = cell.metadata.custom || {};
const metadata: JupyterCellMetadata = JSON.parse(JSON.stringify(cell.metadata.custom || {})) || {};
const cellMetadata = metadata as nbformat.IRawCell;
// metadata property is never optional.
cellMetadata.metadata = cellMetadata.metadata || {};

return metadata;
} else {
const metadata: JupyterCellMetadata = cell.metadata.metadata || {};
const metadata: JupyterCellMetadata = JSON.parse(JSON.stringify(cell.metadata || {})) || { metadata: {} };
// metadata property is never optional.
metadata.metadata = metadata.metadata || {};
return metadata;
Expand Down
72 changes: 72 additions & 0 deletions src/telemetry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2900,6 +2900,38 @@ export class IEventNamePropertyMapping {
* % Time spent in updating the kernel connection.
*/
updateConnection: number;
/**
* Number of code cells in the notebook.
*/
codeCellCount: number;
/**
* Number of md cells in the notebook.
*/
mdCellCount: number;
/**
* Total char length of all text in all code cells.
*/
codeCellCharLength: number;
/**
* Total char length of all text in all md cells.
*/
mdCellCharLength: number;
/**
* Total number of outputs in all cells.
*/
outputCount: number;
/**
* Total bytes of all outputs in all cells.
*/
outputsByteSize: number;
/**
* Total number of attachments
*/
attachmentCount: number;
/**
* Total number of chars in the attachment (generally these are base64 encoded strings).
*/
attachmentCharLength: number;
} & ResourceSpecificTelemetryProperties
> = {
owner: 'donjayamanne',
Expand Down Expand Up @@ -3008,6 +3040,46 @@ export class IEventNamePropertyMapping {
classification: 'SystemMetaData',
purpose: 'FeatureInsight',
isMeasurement: true
},
codeCellCount: {
classification: 'SystemMetaData',
purpose: 'FeatureInsight',
isMeasurement: true
},
mdCellCount: {
classification: 'SystemMetaData',
purpose: 'FeatureInsight',
isMeasurement: true
},
codeCellCharLength: {
classification: 'SystemMetaData',
purpose: 'FeatureInsight',
isMeasurement: true
},
mdCellCharLength: {
classification: 'SystemMetaData',
purpose: 'FeatureInsight',
isMeasurement: true
},
outputCount: {
classification: 'SystemMetaData',
purpose: 'FeatureInsight',
isMeasurement: true
},
outputsByteSize: {
classification: 'SystemMetaData',
purpose: 'FeatureInsight',
isMeasurement: true
},
attachmentCount: {
classification: 'SystemMetaData',
purpose: 'FeatureInsight',
isMeasurement: true
},
attachmentCharLength: {
classification: 'SystemMetaData',
purpose: 'FeatureInsight',
isMeasurement: true
}
}
};
Expand Down
Loading