diff options
Diffstat (limited to 'pw_web/log-viewer/src/log-source.ts')
-rw-r--r-- | pw_web/log-viewer/src/log-source.ts | 92 |
1 files changed, 84 insertions, 8 deletions
diff --git a/pw_web/log-viewer/src/log-source.ts b/pw_web/log-viewer/src/log-source.ts index d000a46d0..6d46f54f8 100644 --- a/pw_web/log-viewer/src/log-source.ts +++ b/pw_web/log-viewer/src/log-source.ts @@ -12,28 +12,43 @@ // License for the specific language governing permissions and limitations under // the License. -import { LogEntry } from './shared/interfaces'; +import { + Field, + LogEntry, + LogSourceEvent, + SourceData, +} from './shared/interfaces'; export abstract class LogSource { private eventListeners: { eventType: string; - listener: (data: LogEntry) => void; + listener: (event: LogSourceEvent) => void; }[]; - constructor() { + protected sourceId: string; + + protected sourceName: string; + + constructor(sourceName: string) { this.eventListeners = []; + this.sourceId = crypto.randomUUID(); + this.sourceName = sourceName; } + abstract start(): void; + + abstract stop(): void; + addEventListener( eventType: string, - listener: (data: LogEntry) => void, + listener: (event: LogSourceEvent) => void, ): void { this.eventListeners.push({ eventType, listener }); } removeEventListener( eventType: string, - listener: (data: LogEntry) => void, + listener: (event: LogSourceEvent) => void, ): void { this.eventListeners = this.eventListeners.filter( (eventListener) => @@ -42,11 +57,72 @@ export abstract class LogSource { ); } - emitEvent(eventType: string, data: LogEntry): void { + emitEvent(event: LogSourceEvent): void { this.eventListeners.forEach((eventListener) => { - if (eventListener.eventType === eventType) { - eventListener.listener(data); + if (eventListener.eventType === event.type) { + eventListener.listener(event); } }); } + + publishLogEntry(logEntry: LogEntry): void { + // Validate the log entry + const validationResult = this.validateLogEntry(logEntry); + if (validationResult !== null) { + console.error('Validation error:', validationResult); + return; + } + + const sourceData: SourceData = { id: this.sourceId, name: this.sourceName }; + logEntry.sourceData = sourceData; + + // Add the name of the log source as a field in the log entry + const logSourceField: Field = { key: 'log_source', value: this.sourceName }; + logEntry.fields.splice(1, 0, logSourceField); + + this.emitEvent({ type: 'log-entry', data: logEntry }); + } + + validateLogEntry(logEntry: LogEntry): string | null { + try { + if (!logEntry.timestamp) { + return 'Log entry has no valid timestamp'; + } + if (!Array.isArray(logEntry.fields)) { + return 'Log entry fields must be an array'; + } + if (logEntry.fields.length === 0) { + return 'Log entry fields must not be empty'; + } + + for (const field of logEntry.fields) { + if (!field.key || typeof field.key !== 'string') { + return 'Invalid field key'; + } + if ( + field.value === undefined || + (typeof field.value !== 'string' && + typeof field.value !== 'boolean' && + typeof field.value !== 'number' && + typeof field.value !== 'object') + ) { + return 'Invalid field value'; + } + } + + if ( + logEntry.severity !== undefined && + typeof logEntry.severity !== 'string' + ) { + return 'Invalid severity value'; + } + + return null; + } catch (error) { + if (error instanceof Error) { + console.error('Validation error:', error.message); + } + return 'An unexpected error occurred during validation'; + } + } } |