1
0
mirror of https://github.com/akpaevj/onecmonitor.git synced 2026-06-19 22:59:58 +02:00
Files
onecmonitor/onecmonitor-server/Scripts/techLog.ts
T
akpaev.e cd9542bd79 init
2025-03-29 01:33:55 +03:00

266 lines
7.8 KiB
TypeScript

import {CallGraphMember, LockWaitingMember, LockWaitingMemberType} from "./models";
import {DataGroup, DataItem, Timeline, TimelineOptions} from "vis-timeline";
import * as vis from "visjs-network";
import * as ace from 'ace-builds/src-noconflict/ace';
import 'ace-builds/src-noconflict/theme-one_dark';
import 'ace-builds/src-noconflict/mode-xml';
import 'ace-builds/src-noconflict/mode-sql';
import {setUrlParameterValue} from "./common";
export function applyTechLogFilter(filter: string) {
setUrlParameterValue('filter', filter);
}
export function initAceEditor(editorContainer: Element, contentContainer: HTMLTextAreaElement, mode: string, heightToContent: Boolean = false) {
let editor = ace.edit(editorContainer, {
mode: `ace/mode/${mode}`,
selectionStyle: "text",
theme: 'ace/theme/one_dark',
enableLiveAutocompletion: true,
autoScrollEditorIntoView: false
});
if (mode === 'sql') {
editor.setOption('enableSnippets', true);
//let langTools = ace.require('ace/ext/language_tools');
//langTools.addCompleter(getClickHouseCompleter());
}
if (heightToContent) {
editor.container.style.minHeight = 'inherit';
editor.setOption('maxLines', 1);
editor.setOption('showLineNumbers', false);
editor.setOption('highlightActiveLine', false);
}
editor.setOptions({
autoScrollEditorIntoView: true,
copyWithEmptySelection: true
});
// set value from input to code editor
editor.setValue(contentContainer.value);
// set code editor value to input when it's being changed
editor.on('change', function () {
contentContainer.innerHTML = editor.getValue();
});
}
function getClickHouseCompleter() {
let properties = [
'Id',
'StartDateTime',
'DateTime',
'Duration',
'EventName',
'Level',
'SessionId',
'CallId',
'TClientId',
'TConnectId',
'PProcessName',
'WaitConnections',
'Locks',
'AgentId',
'SeanceId',
'Folder',
'File',
'EndPosition',
'Properties[\'\']'
];
return {
getCompletions: function (editor, session, pos, prefix, callback) {
callback(null, properties.map(function (name) {
return {
value: name,
meta: "Property"
};
}));
}
};
}
export function initCallTimeline(chainStr: string) {
let chain: Array<CallGraphMember> = JSON.parse(chainStr);
let container = document.querySelector('#timeline-container') as HTMLCanvasElement;
let options: TimelineOptions = {
format: {
minorLabels: {
millisecond: 's.SSSSSS'
}
},
editable: false,
multiselect: true
};
let groups: DataGroup[] = new Array<DataGroup>();
let items: DataItem[] = new Array<DataItem>();
chain.forEach(value => {
let groupId = "";
let item: DataItem;
if (value.IsCombinedEvent) {
let start = new Date(value.CombinedEventStartDateTime + "Z");
let end = new Date(value.CombinedEventFinishDateTime + "Z");
groupId = value.CombinedEventGroup;
item = {
id: value.CombinedEvents[0],
content: value.CombinedEventName,
start: start,
end: end,
group: groupId
};
} else {
let start = new Date(value.Event.start_date_time + "Z");
let end = new Date(value.Event.date_time + "Z");
groupId = value.Event.props['process'];
item = {
id: value.Event.id,
content: value.Event.event_name,
start: start,
end: end,
group: groupId
};
}
if (groups.find(c => c.id == groupId) == undefined) {
groups.push({
id: groupId,
content: groupId
});
}
items.push(item);
});
const timeline = new Timeline(container, items, groups, options);
}
export function initLockWaitingGraph(graphStr: string) {
let graph = new Map<string, LockWaitingMember>(Object.entries(JSON.parse(graphStr)));
let container = document.querySelector('#graph-container') as HTMLElement;
let nodes = [];
let edges = [];
let minNodeSize = 10;
let maxNodeSize = 30;
let minEventDuration = Number.MAX_VALUE;
let maxEventDuration = 0;
graph.forEach(c => {
minEventDuration = Math.min(minEventDuration, c.Event.real_duration);
maxEventDuration = Math.max(maxEventDuration, c.Event.real_duration);
});
graph.forEach(value => {
let nodeColor = getLockWaitingNodeColor(value.MemberType);
nodes.push({
id: value.Event.id,
label: value.Event.event_name,
color: nodeColor,
shape: 'circle',
size: getSize(minNodeSize, maxNodeSize, minEventDuration, maxEventDuration, value.Event.real_duration)
});
value.DirectCulprits.forEach(culprit => {
edges.push({ from: value.Event.id, to: culprit });
});
value.IndirectCulprits.forEach(culprit => {
edges.push({ from: value.Event.id, to: culprit });
});
});
let data = {
nodes: nodes,
edges: edges,
};
var options = {
height: "400px"
};
var network = new vis.Network(container, data, options);
}
export function initLockWaitingTimeline(graphStr: string) {
let graph = new Map<string, LockWaitingMember>(Object.entries(JSON.parse(graphStr)));
let container = document.querySelector('#timeline-container') as HTMLElement;
let options: TimelineOptions = {
format: {
minorLabels: {
millisecond: 's.SSSSSS'
}
},
editable: false,
multiselect: true
};
let items: DataItem[] = new Array<DataItem>();
graph.forEach(value => {
let start = new Date(value.Event.start_date_time + "Z");
let end = new Date(value.LockAffectEndDateTime + "Z");
items.push({
id: value.Event.id,
content: `${value.Event.event_name} (${value.Event.t_connect_id})`,
start: start,
end: end,
className: getLockWaitingMemberClass(value.MemberType)
});
});
const timeline = new Timeline(container, items, options);
timeline.on('select', properties => {
let items: Array<string> = properties.items;
document.querySelectorAll('[id^="details-"]').forEach(value => {
if (items.includes(value.id.replace('details-', ''))) {
value.removeAttribute('hidden');
} else {
value.setAttribute('hidden', '');
}
});
});
}
function getLockWaitingMemberClass(type: LockWaitingMemberType) {
if (type === LockWaitingMemberType.victim) {
return 'om-victim-bg';
} else if (type === LockWaitingMemberType.directCulprit) {
return 'om-direct-culprit-bg';
} else {
return 'om-indirect-culprit-bg';
}
}
function getLockWaitingNodeColor(type: LockWaitingMemberType) {
if (type === LockWaitingMemberType.victim) {
return '#ffb9b9';
} else if (type === LockWaitingMemberType.directCulprit) {
return '#b3d3ff';
} else {
return '#e2b2ff';
}
}
function getSize(minValue: number, maxValue: number, minNatValue: number, maxNatValue: number, natValue: number): number {
const valueRange = maxValue - minValue;
const realValueRange = maxNatValue - minNatValue;
const percents = (100 / realValueRange) * (natValue - minNatValue);
return minValue + (valueRange * (percents / 100));
}