diff --git a/docs/Loki.md b/docs/Loki.md index 52480ce..103b9b4 100644 --- a/docs/Loki.md +++ b/docs/Loki.md @@ -61,8 +61,8 @@ interface LokiQueryStreamOptions extends LokiQueryOpt The response is described by the following interface: ```ts -export interface QueryRangeResponse { - values: LokiLiteralPattern[]; +interface QueryRangeLogsResponse { + logs: LokiLiteralPattern[]; timerange: TimeRange | null; } ``` @@ -92,14 +92,14 @@ for (const { stream, values } of logs) { The response is described by the following interface: ```ts -interface QueryRangeStreamResponse { - logs: LokiStreamResult>[]; - timerange: TimeRange | null; +interface LokiStream { + stream: Record; + values: [unixEpoch: number, log: T][]; } -interface LokiStreamResult { - stream: Record; - values: [unixEpoch: number, value: T][]; +interface QueryRangeStreamResponse { + streams: LokiStream>[]; + timerange: TimeRange | null; } ``` @@ -118,14 +118,14 @@ count_over_time({ label="value" }[5m]) The response is described by the following interface: ```ts -interface QueryRangeMatrixResponse { - logs: LokiMatrix[]; - timerange: TimeRange | null; -} - interface LokiMatrix { metric: Record; - values: [unixEpoch: number, value: string][]; + values: [unixEpoch: number, metric: string][]; +} + +interface QueryRangeMatrixResponse { + metrics: LokiMatrix[]; + timerange: TimeRange | null; } ``` @@ -223,7 +223,8 @@ async series>( ``` ## Pattern usage -**queryRange** and **queryRangeStream** API allow the usage of pattern. + +**queryRange** and **queryRangeStream** APIs allow the usage of pattern. ```ts import { GrafanaApi } from "@myunisoft/loki"; diff --git a/src/class/Loki.class.ts b/src/class/Loki.class.ts index 45b9f06..8820360 100644 --- a/src/class/Loki.class.ts +++ b/src/class/Loki.class.ts @@ -17,9 +17,7 @@ import * as utils from "../utils.js"; import { LokiStandardBaseResponse, RawQueryRangeResponse, - LokiStream, - LokiMatrix, - QueryRangeResponse, + QueryRangeLogsResponse, QueryRangeStreamResponse, QueryRangeMatrixResponse } from "../types.js"; @@ -92,7 +90,7 @@ export class Loki { this.credential = credential; } - #fetchQueryRange( + #fetchQueryRange( logQL: LogQL | string, options: LokiQueryOptions = {} ): Promise>> { @@ -121,13 +119,13 @@ export class Loki { throw new Error("Log queries must use `queryRangeStream` method"); } - const { data } = await this.#fetchQueryRange( + const { data } = await this.#fetchQueryRange<"matrix">( logQL, options ); return { - logs: data.data.result, + metrics: data.data.result, timerange: utils.streamOrMatrixTimeRange(data.data.result) }; } @@ -144,13 +142,13 @@ export class Loki { const parser: PatternShape = pattern instanceof NoopPattern ? pattern : new Pattern(pattern); - const { data } = await this.#fetchQueryRange( + const { data } = await this.#fetchQueryRange<"streams">( logQL, options ); return { - logs: data.data.result.map((result) => { + streams: data.data.result.map((result) => { return { stream: result.stream, values: result.values @@ -165,22 +163,22 @@ export class Loki { async queryRange( logQL: LogQL | string, options: LokiQueryStreamOptions = {} - ): Promise> { + ): Promise> { const { pattern = new NoopPattern() } = options; const parser: PatternShape = pattern instanceof NoopPattern ? pattern : new Pattern(pattern); - const { data } = await this.#fetchQueryRange(logQL, options); + const { data } = await this.#fetchQueryRange<"streams">(logQL, options); const inlinedLogs = utils.inlineLogs(data); if (inlinedLogs === null) { return { - values: [], timerange: null + logs: [], timerange: null }; } return { - values: parser.executeOnLogs(inlinedLogs.values) as any[], + logs: parser.executeOnLogs(inlinedLogs.values) as any[], timerange: inlinedLogs.timerange }; } diff --git a/src/types.ts b/src/types.ts index c6f1311..f15a63c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -7,80 +7,86 @@ import { // Import Internal Dependencies import { TimeRange } from "./utils.js"; -export interface LokiStream { - stream: Record; - values: [unixEpoch: number, log: string][]; -} - -export interface LokiMatrix { - metric: Record; - values: [unixEpoch: number, value: string][]; +export type LokiStandardBaseResponse = { + status: "failed"; +} | { + status: "success"; + data: S; } -export interface LokiStreamResult { - stream: Record; - values: [unixEpoch: number, value: T][]; +export interface LokiQueryRangeStats { + summary: { + bytesProcessedPerSecond: number; + linesProcessedPerSecond: number; + totalBytesProcessed: number; + totalLinesProcessed: number; + execTime: number; + }; + store: { + totalChunksRef: number; + totalChunksDownloaded: number; + chunksDownloadTime: number; + headChunkBytes: number; + headChunkLines: number; + decompressedBytes: number; + decompressedLines: number; + compressedBytes: number; + totalDuplicates: number; + }; + ingester: { + totalReached: number; + totalChunksMatched: number; + totalBatches: number; + totalLinesSent: number; + headChunkBytes: number; + headChunkLines: number; + decompressedBytes: number; + decompressedLines: number; + compressedBytes: number; + totalDuplicates: number; + } } -export interface RawQueryRangeResponse { +interface RawQueryRangeTemplate< + Type extends "matrix" | "streams", + Result extends LokiMatrix | LokiStream +> { status: "success"; data: { - resultType: "matrix" | "streams"; - result: T[]; - stats: { - summary: { - bytesProcessedPerSecond: number; - linesProcessedPerSecond: number; - totalBytesProcessed: number; - totalLinesProcessed: number; - execTime: number; - }; - store: { - totalChunksRef: number; - totalChunksDownloaded: number; - chunksDownloadTime: number; - headChunkBytes: number; - headChunkLines: number; - decompressedBytes: number; - decompressedLines: number; - compressedBytes: number; - totalDuplicates: number; - }; - ingester: { - totalReached: number; - totalChunksMatched: number; - totalBatches: number; - totalLinesSent: number; - headChunkBytes: number; - headChunkLines: number; - decompressedBytes: number; - decompressedLines: number; - compressedBytes: number; - totalDuplicates: number; - } - }; + resultType: Type; + result: Result[]; + stats: LokiQueryRangeStats; } } -export type LokiStandardBaseResponse = { - status: "failed"; -} | { - status: "success"; - data: S; -} +export type RawQueryRangeResponse = T extends "matrix" ? + RawQueryRangeTemplate : + RawQueryRangeTemplate; + +export type LokiLabels = Record; -export interface QueryRangeResponse { - values: LokiLiteralPattern[]; +export interface QueryRangeLogsResponse { + logs: LokiLiteralPattern[]; timerange: TimeRange | null; } +export interface LokiStream { + stream: LokiLabels; + values: [unixEpoch: number, log: T][]; +} + export interface QueryRangeStreamResponse { - logs: LokiStreamResult>[]; + streams: LokiStream>[]; timerange: TimeRange | null; } +export interface LokiMatrix { + metric: LokiLabels; + values: [unixEpoch: number, metric: string][]; +} + export interface QueryRangeMatrixResponse { - logs: LokiMatrix[]; + metrics: LokiMatrix[]; timerange: TimeRange | null; } diff --git a/src/utils.ts b/src/utils.ts index 9d71f3d..ee076bf 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -37,7 +37,7 @@ export function transformStreamOrMatrixValue( export type TimeRange = [first: number, last: number]; export function inlineLogs( - result: RawQueryRangeResponse + result: RawQueryRangeResponse<"streams"> ): null | { values: string[], timerange: TimeRange } { if (result.status !== "success") { return null; diff --git a/test/Loki.spec.ts b/test/Loki.spec.ts index 3231059..1b0126f 100644 --- a/test/Loki.spec.ts +++ b/test/Loki.spec.ts @@ -82,7 +82,7 @@ describe("GrafanaApi.Loki", () => { const sdk = new GrafanaApi({ remoteApiURL: kDummyURL }); const result = await sdk.Loki.queryRangeMatrix("count_over_time({app='foo'} [5m])"); - const resultLogs = result.logs[0]!; + const resultLogs = result.metrics[0]!; assert.ok( resultLogs.values.every((arr) => typeof arr[0] === "number") @@ -132,9 +132,9 @@ describe("GrafanaApi.Loki", () => { const result = await sdk.Loki.queryRangeStream("{app='foo'}", { pattern: "hello ''" }); - const resultLogs = result.logs[0]!; + const resultLogs = result.streams[0]!; - assert.strictEqual(result.logs.length, 1); + assert.strictEqual(result.streams.length, 1); assert.deepEqual( resultLogs.values[0][1], { name: "Thomas" } @@ -156,7 +156,7 @@ describe("GrafanaApi.Loki", () => { const sdk = new GrafanaApi({ remoteApiURL: kDummyURL }); const result = await sdk.Loki.queryRangeStream("{app='foo'}"); - const resultLogs = result.logs[0]!; + const resultLogs = result.streams[0]!; assert.ok( resultLogs.values.every((arr) => typeof arr[0] === "number") @@ -186,7 +186,7 @@ describe("GrafanaApi.Loki", () => { }); assert.deepEqual( - result.logs, + result.streams, expectedLogs ); }); @@ -207,7 +207,7 @@ describe("GrafanaApi.Loki", () => { const result = await sdk.Loki.queryRangeStream("{app='foo'}"); assert.deepEqual( - result.logs, + result.streams, expectedLogs ); }); @@ -237,7 +237,7 @@ describe("GrafanaApi.Loki", () => { const result = await sdk.Loki.queryRange("{app='foo'}"); assert.deepEqual( - result.values, + result.logs, expectedLogs.slice(0).reverse() ); }); @@ -258,9 +258,9 @@ describe("GrafanaApi.Loki", () => { const result = await sdk.Loki.queryRange("{app='foo'}", { pattern: "hello ''" }); - assert.strictEqual(result.values.length, 1); + assert.strictEqual(result.logs.length, 1); assert.deepEqual( - result.values[0], + result.logs[0], { name: "Thomas" } ); }); diff --git a/test/utils/logs.factory.ts b/test/utils/logs.factory.ts index c0df836..053d81d 100644 --- a/test/utils/logs.factory.ts +++ b/test/utils/logs.factory.ts @@ -1,13 +1,12 @@ // Import Internal Dependencies import { - RawQueryRangeResponse, - LokiMatrix + RawQueryRangeResponse } from "../../src/index.js"; export function mockStreamResponse( logs: string[], unixGenerator = getNanoSecTime -): RawQueryRangeResponse { +): RawQueryRangeResponse<"streams"> { return { status: "success", data: { @@ -26,7 +25,7 @@ export function mockStreamResponse( export function mockMatrixResponse( logs: string[], unixGenerator = getNanoSecTime -): RawQueryRangeResponse { +): RawQueryRangeResponse<"matrix"> { return { status: "success", data: {