Log: Log to Clarence machine, add setting for user email

This commit is contained in:
Andrew Head 2019-02-22 16:24:37 -08:00
Родитель d47c210736
Коммит b0082f2421
5 изменённых файлов: 86 добавлений и 30 удалений

Просмотреть файл

@ -22,6 +22,13 @@ jupyter lab --watch # launch Jupyter Lab, automatically re-load extens
These setup instructions have been successfully completed with Node v9.5.0.
### Upload the extension
```bash
npm login
npm publish --access=restricted # make this public eventually
```
### Pre-alpha Jupyter notebook version
This project was initially developed as a Jupyter notebook extension. It is not being maintained, as it requires access to the internal API, including parts that change across minor versions. Still, if you want to build and install the notebook version, run these commands:

Просмотреть файл

@ -1,7 +1,7 @@
{
"name": "gathering",
"name": "@andrewhead/gather",
"version": "0.2.0",
"description": "Add live programming to Jupyter cells",
"description": "Tools for cleaning and recovering code in Jupyter Lab",
"author": "",
"main": "lib/lab/index.js",
"keywords": [
@ -20,11 +20,13 @@
"test": "mocha -r ts-node/register src/test/*.test.ts"
},
"files": [
"schema/*.json",
"lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}",
"style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}"
],
"jupyterlab": {
"extension": true
"extension": true,
"schemaDir": "schema"
},
"dependencies": {
"@jupyterlab/application": "^0.19.1",

23
schema/plugin.json Normal file
Просмотреть файл

@ -0,0 +1,23 @@
{
"jupyter.lab.setting-icon-label": "Gather",
"title": "Code Gathering",
"description": "Settings for gathering code",
"definitions": {
"gatheringConfig": {
"userEmail": {
"type": ["string", "null", "undefined"]
}
}
},
"properties": {
"gatheringConfig": {
"title": "Code Gathering Configuration",
"description": "Settings for gathering cdoe",
"default": {
"userEmail": null
}
}
},
"additionalProperties": false,
"type": "object"
}

Просмотреть файл

@ -11,7 +11,7 @@ import { MarkerManager } from '../packages/cell';
import { GatherController, GatherModel, GatherState } from '../packages/gather';
import { DataflowAnalyzer } from '../slicing/DataflowAnalysis';
import { ExecutionLogSlicer } from '../slicing/ExecutionSlicer';
import { log } from '../utils/log';
import { log, initLogger } from '../utils/log';
import { ExecutionLogger } from './execution-logger';
import { GatherModelRegistry, getGatherModelForActiveNotebook } from './gather-registry';
import { NotifactionExtension as NotificationExtension } from './notification';
@ -20,12 +20,13 @@ import { ResultsHighlighter } from './results';
import '../../style/index.css';
import '../../style/lab-vars.css';
import { Clipboard } from './gather-actions';
import { ISettingRegistry } from '@jupyterlab/coreutils';
const extension: JupyterLabPlugin<void> = {
activate: activateExtension,
id: 'gather:gatherPlugin',
requires: [ICommandPalette, INotebookTracker, IDocumentManager],
requires: [ICommandPalette, INotebookTracker, IDocumentManager, ISettingRegistry],
autoStart: true
};
@ -85,7 +86,8 @@ function saveHistoryOnNotebookSave(notebook: NotebookPanel, gatherModel: GatherM
});
}
function activateExtension(app: JupyterLab, palette: ICommandPalette, notebooks: INotebookTracker, documentManager: IDocumentManager) {
function activateExtension(app: JupyterLab, palette: ICommandPalette, notebooks: INotebookTracker,
documentManager: IDocumentManager, settingRegistry: ISettingRegistry) {
console.log('Activating code gathering tools...');
@ -163,6 +165,9 @@ function activateExtension(app: JupyterLab, palette: ICommandPalette, notebooks:
});
*/
// settingRegistry.set("gather:plugin", "gatheringConfig", { email: "andrewhead@berkeley.edu" });
initLogger(settingRegistry);
console.log('Code gathering tools have been activated.');
}

Просмотреть файл

@ -1,3 +1,7 @@
import { ISettingRegistry } from "@jupyterlab/coreutils";
import { JSONExt, JSONObject } from "@phosphor/coreutils";
import * as $ from "jquery";
/**
* Interface for calling Ajax.
*/
@ -14,7 +18,8 @@ export interface AjaxCaller {
/**
* Utility for calling Jupyter server using AJAX.
*/
let _ajaxCaller: AjaxCaller = undefined;
// let _ajaxCaller: AjaxCaller = undefined;
let _settingRegistry: ISettingRegistry;
let _showedLogUninitializedError = false;
/**
@ -22,8 +27,9 @@ let _showedLogUninitializedError = false;
* logger is that notebook requires requests with XSRF tokens. The right Ajax caller is the one
* that's built into Jupyter notebook or lab that passes these tokens.
*/
export function initLogger(ajaxCaller: AjaxCaller) {
_ajaxCaller = ajaxCaller;
export function initLogger(settingRegistry: ISettingRegistry) {
// _ajaxCaller = ajaxCaller;
_settingRegistry = settingRegistry;
}
let _statePollers: IStatePoller[] = [];
@ -54,6 +60,9 @@ export function log(eventName: string, data?: any) {
data = data || {};
let _ajaxCaller = $;
let LOG_ENDPOINT = 'https://clarence.eecs.berkeley.edu';
if (_ajaxCaller == undefined) {
if (_showedLogUninitializedError == false) {
console.info("Logger not initialized, skipping logging");
@ -66,29 +75,39 @@ export function log(eventName: string, data?: any) {
let postData: any = {
timestamp: new Date().toISOString(),
event: eventName,
data: data
data: data,
userEmail: undefined,
};
if (_settingRegistry != undefined || _settingRegistry != null) {
_settingRegistry.get('gather:plugin', 'gatheringConfig').then((data) => {
if (JSONExt.isObject(data.composite)) {
let dataCompositeObject = data.composite as JSONObject;
postData.userEmail = dataCompositeObject['userEmail'];
// Poll for additional data from each state poller.
for (let poller of _statePollers) {
let pollData = poller.poll();
for (let k in pollData) {
if (pollData.hasOwnProperty(k)) {
postData[k] = pollData[k];
// Poll for additional data from each state poller.
for (let poller of _statePollers) {
let pollData = poller.poll();
for (let k in pollData) {
if (pollData.hasOwnProperty(k)) {
postData[k] = pollData[k];
}
}
}
// Submit data to logger endpoint.
_ajaxCaller.ajax(LOG_ENDPOINT + "/save", {
// If there is any sensitive data to be logged, it should first be cleaned through a
// `toJSON` method defined on a class, or manually before passing it into this method.
// Earlier, we used the replacer argument to JSON.stringify, but it takes too much time
// to apply replacers to every value in the resulting JSON.
data: JSON.stringify(postData),
method: "POST",
error: (_: any, textStatus: string, errorThrown: string) => {
console.error("Failed to log", textStatus, errorThrown);
}
});
}
}
});
}
// Submit data to logger endpoint.
_ajaxCaller.ajax("/log", {
// If there is any sensitive data to be logged, it should first be cleaned through a
// `toJSON` method defined on a class, or manually before passing it into this method.
// Earlier, we used the replacer argument to JSON.stringify, but it takes too much time
// to apply replacers to every value in the resulting JSON.
data: JSON.stringify(postData),
method: "POST",
error: (_: any, textStatus: string, errorThrown: string) => {
console.error("Failed to log", textStatus, errorThrown);
}
});
}