Skip to content

Commit

Permalink
Improve performance
Browse files Browse the repository at this point in the history
  • Loading branch information
felixbrucker committed Feb 26, 2024
1 parent 4c1d779 commit a95c186
Show file tree
Hide file tree
Showing 12 changed files with 95 additions and 22 deletions.
10 changes: 6 additions & 4 deletions src/analyze-chia-log.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {detectPlotNfts, PlotNft} from './analyzer/plot-nfts.js'
import {detectReOrgs, ReOrg} from './analyzer/re-org.js'
import {detectSpSpam, SpSpam} from './analyzer/sp-spam.js'
import {detectUnsupportedDb} from './analyzer/unsupported-db.js'
import {grouping} from './util/grouping.js'

export interface LogAnalyzationResult {
groupedCriticalLines: GroupedLines
Expand All @@ -36,11 +37,12 @@ export interface AnalyzeOptions {

export function analyzeChiaLog(logFileContent: string, options?: AnalyzeOptions): LogAnalyzationResult {
const logLines = mapLogFileContentsToLogLines(logFileContent)
const logLinesByLogLevel = grouping(logLines, logLine => logLine.logLevel)

const criticalLogLines = logLines.filter(logLine => logLine.logLevel === LogLevel.critical)
const errorLogLines = logLines.filter(logLine => logLine.logLevel === LogLevel.error)
const warningLogLines = logLines.filter(logLine => logLine.logLevel === LogLevel.warning)
const infoLogLines = logLines.filter(logLine => logLine.logLevel === LogLevel.info)
const criticalLogLines = logLinesByLogLevel.get(LogLevel.critical) ?? []
const errorLogLines = logLinesByLogLevel.get(LogLevel.error) ?? []
const warningLogLines = logLinesByLogLevel.get(LogLevel.warning) ?? []
const infoLogLines = logLinesByLogLevel.get(LogLevel.info) ?? []
const reversedInfoLogLines = infoLogLines
.slice()
.reverse()
Expand Down
5 changes: 3 additions & 2 deletions src/analyzer/corrupt-plot.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import '../extensions/array-extensions.js'

import {LogLine} from '../types/log-line.js'

const plotRegex = /^File: (.+\.plot) Plot ID.*$/
Expand All @@ -9,15 +11,14 @@ export interface CorruptPlot {

export function detectCorruptPlots(errorLogLines: LogLine[]): CorruptPlot[] {
const plotsWithErrors = errorLogLines
.map(logLine => {
.mapAndFilter(logLine => {
const matches = logLine.message.match(plotRegex)
if (matches === null || matches.length !== 2) {
return
}

return matches[1]
})
.filter((plotPath): plotPath is string => plotPath !== undefined)

const numberOfErrorsByPlotPath = plotsWithErrors.reduce((agg, plotPath) => {
const errorCount = agg.get(plotPath) ?? 0
Expand Down
5 changes: 3 additions & 2 deletions src/analyzer/duplicate-plot.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import '../extensions/array-extensions.js'

import {LogLine} from '../types/log-line.js'

const duplicatePlotRegex = /^Have multiple copies of the plot (.+\.plot) in \[(.*)].*$/
Expand All @@ -9,7 +11,7 @@ export interface DuplicatePlot {

export function detectDuplicatePlots(warningLogLines: LogLine[]): DuplicatePlot[] {
return warningLogLines
.map((logLine): DuplicatePlot|undefined => {
.mapAndFilter((logLine): DuplicatePlot|undefined => {
if (logLine.file !== 'chia.plotting.manager') {
return
}
Expand All @@ -23,5 +25,4 @@ export function detectDuplicatePlots(warningLogLines: LogLine[]): DuplicatePlot[
plotPaths: matches[2].split(', ').map(plotPath => plotPath.trim().replaceAll(`'`, '').replaceAll('\\\\', '\\')),
}
})
.filter((duplicatePlot): duplicatePlot is DuplicatePlot => duplicatePlot !== undefined)
}
5 changes: 3 additions & 2 deletions src/analyzer/plot-nfts.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import '../extensions/array-extensions.js'

import {LogLine} from '../types/log-line.js'
import {convertPuzzleHashToAddress} from '../util/puzzle-hash.js'

Expand All @@ -12,7 +14,7 @@ export interface PlotNft {

export function detectPlotNfts(infoLogLines: LogLine[]): PlotNft[] {
const plotNfts = infoLogLines
.map((logLine): PlotNft|undefined => {
.mapAndFilter((logLine): PlotNft|undefined => {
if (logLine.file !== 'chia.farmer.farmer') {
return
}
Expand All @@ -38,7 +40,6 @@ export function detectPlotNfts(infoLogLines: LogLine[]): PlotNft[] {
payoutAddress,
}
})
.filter((plotNft): plotNft is PlotNft => plotNft !== undefined)
.reduce((agg, plotNft) => {
agg.set(plotNft.launcherId, plotNft)

Expand Down
5 changes: 3 additions & 2 deletions src/analyzer/re-org.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import '../extensions/array-extensions.js'

import {LogLine} from '../types/log-line.js'
import {toChiaLogDate} from '../util/to-chia-log-date.js'

Expand All @@ -12,7 +14,7 @@ export interface ReOrg {

export function detectReOrgs(infoLogLines: LogLine[]): ReOrg[] {
return infoLogLines
.map((logLine): ReOrg|undefined => {
.mapAndFilter((logLine): ReOrg|undefined => {
if (logLine.file !== 'chia.full_node.full_node') {
return
}
Expand All @@ -32,5 +34,4 @@ export function detectReOrgs(infoLogLines: LogLine[]): ReOrg[] {
}
}
})
.filter((reOrg): reOrg is ReOrg => reOrg !== undefined)
}
5 changes: 3 additions & 2 deletions src/analyzer/slow-block-validation.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import '../extensions/array-extensions.js'

import {LogLine} from '../types/log-line.js'
import {Dayjs} from 'dayjs'

Expand Down Expand Up @@ -29,7 +31,7 @@ const slowBlockValidationRegex = /^Block validation time: ([0-9]+\.[0-9]+) secon

export function analyzeForSlowBlockValidation(warningLogLines: LogLine[]): SlowBlockValidationResult {
const blockValidationWarnings = warningLogLines
.map((logLine): BlockValidationWarning|undefined => {
.mapAndFilter((logLine): BlockValidationWarning|undefined => {
const matches = logLine.message.match(slowBlockValidationRegex)
if (matches === null || (matches.length !== 5 && matches.length !== 3)) {
return
Expand All @@ -43,7 +45,6 @@ export function analyzeForSlowBlockValidation(warningLogLines: LogLine[]): SlowB
percentFull: matches.length === 5 ? parseFloat(matches[4]) : undefined,
}
})
.filter((warning): warning is BlockValidationWarning => warning !== undefined)

const slowBlockValidationWarnings = blockValidationWarnings.filter(warning => warning.blockValidationTimeInSeconds >= 4)
if (slowBlockValidationWarnings.length === 0) {
Expand Down
5 changes: 3 additions & 2 deletions src/analyzer/slow-plots.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import '../extensions/array-extensions.js'

import {LogLine} from '../types/log-line.js'
import {Dayjs} from 'dayjs'

Expand All @@ -10,7 +12,7 @@ export interface SlowPlotScan {

export function detectSlowPlotScans(infoLogLines: LogLine[]): SlowPlotScan[] {
return infoLogLines
.map((logLine): SlowPlotScan|undefined => {
.mapAndFilter((logLine): SlowPlotScan|undefined => {
const matches = logLine.message.match(plotScanRegex)
if (matches === null || matches.length !== 3) {
return
Expand All @@ -21,5 +23,4 @@ export function detectSlowPlotScans(infoLogLines: LogLine[]): SlowPlotScan[] {
durationInSeconds: parseFloat(matches[2]),
}
})
.filter((slowPlotScan): slowPlotScan is SlowPlotScan => slowPlotScan !== undefined && slowPlotScan.durationInSeconds > 20)
}
5 changes: 3 additions & 2 deletions src/analyzer/startup-info.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import '../extensions/array-extensions.js'

import {LogLine} from '../types/log-line.js'
import {Dayjs} from 'dayjs'
import {mapFind} from '../util/map-find.js'
Expand Down Expand Up @@ -141,15 +143,14 @@ export function detectStartupInfo(infoLogLines: LogLine[], reversedInfoLogLines:
}

const startedServices = infoLogLines
.map(logLine => {
.mapAndFilter(logLine => {
const matches = logLine.message.match(startingServiceRegex)
if (matches === null || matches.length !== 2) {
return
}

return matches[1]
})
.filter((serviceName): serviceName is string => serviceName !== undefined)

const databaseInfo = mapFind<LogLine, DatabaseInfo|undefined>(
infoLogLinesSinceStartup,
Expand Down
17 changes: 17 additions & 0 deletions src/extensions/array-extensions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
declare global {
export interface Array<T> {
mapAndFilter<V>(mapper: (value: T) => V|undefined): V[]
}
}

Array.prototype.mapAndFilter = function<T, V>(mapper: (value: T) => V|undefined): V[] {
const result: V[] = []
this.forEach((element: T) => {
const mapped = mapper(element)
if (mapped !== undefined) {
result.push(mapped)
}
})

return result
}
32 changes: 32 additions & 0 deletions src/extensions/map-extensions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
declare global {
export interface Map<K, V> {
getWithDefault(key: K, defaultValue: V): V
}
export interface MapConstructor {
fromObject<V>(obj: Record<string, V>): Map<string, V>
fromArray<V>(array: Array<V>, mapToKey: (value: V) => string): Map<string, V>
}
}

Map.prototype.getWithDefault = function<K, V>(key: K, defaultValue: V): V {
if (this.has(key)) {
return this.get(key)
}

this.set(key, defaultValue)

return defaultValue
}

Map.fromObject = function<V>(obj: Record<string, V>): Map<string, V> {
return new Map(Object.entries(obj))
}

Map.fromArray = function<V>(array: Array<V>, mapToKey: (value: V) => string): Map<string, V> {
const map = new Map<string, V>()
for (const value of array) {
map.set(mapToKey(value), value)
}

return map
}
8 changes: 4 additions & 4 deletions src/log-line-mapper.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import './extensions/array-extensions.js'

import dayjs from 'dayjs'
import {LogLevel, LogLine} from './types/log-line.js'

Expand All @@ -10,7 +12,7 @@ export function mapLogFileContentsToLogLines(logFileContents: string): LogLine[]
const logLines: string[] = []
for (const line of lines) {
if (line.match(logLineTimestampRegex) === null) {
if (logLines.length >= 0) {
if (logLines.length > 0) {
logLines[logLines.length -1] = `${logLines[logLines.length - 1]}\n${line}`

continue
Expand All @@ -19,9 +21,7 @@ export function mapLogFileContentsToLogLines(logFileContents: string): LogLine[]
logLines.push(line)
}

return logLines
.map(mapToLogLine)
.filter((logLine): logLine is LogLine => logLine !== undefined)
return logLines.mapAndFilter(mapToLogLine)
}


Expand Down
15 changes: 15 additions & 0 deletions src/util/grouping.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import '../extensions/map-extensions.js'

export function grouping<ElementType>(
elements: ElementType[],
mapper: (value: ElementType) => string,
): Map<string, ElementType[]> {
return elements.reduce((result, element) => {
const key = mapper(element)
result
.getWithDefault(key, [])
.push(element)

return result
}, new Map<string, ElementType[]>)
}

0 comments on commit a95c186

Please sign in to comment.