feat: implement history push mutation and enhanced MCP logging

- Implement pushHistory mutation to support pushing telemetry data to Zabbix trapper items.

- Add VERBOSITY and MCP_LOG_* environment variables for controllable request/response logging in both API and MCP server.

- Enhance ZabbixRESTDataSource with better session handling and error logging.

- Update ZabbixHistory datasource to support history push operations.

- Expand documentation with new cookbook recipes and MCP integration guides.

- Add integration tests for history pushing (src/test/history_push*).

- Reorganize documentation, moving technical product info PDF to docs/use-cases/.

- Update GraphQL generated types and VCR templates.
This commit is contained in:
Andreas Hilbig 2026-02-03 13:29:42 +01:00
parent b646b8c606
commit 7c2dee2b6c
28 changed files with 6036 additions and 3088 deletions

View file

@ -1,7 +1,10 @@
import {SortOrder, StorageItemType} from "../schema/generated/graphql.js";
import {ParsedArgs, ZabbixParams, ZabbixRequest, ZabbixResult} from "./zabbix-request.js";
import {ApiError, SortOrder, StorageItemType} from "../schema/generated/graphql.js";
import {isZabbixErrorResult, ParsedArgs, ZabbixErrorResult, ZabbixParams, ZabbixRequest, ZabbixResult} from "./zabbix-request.js";
import {ZabbixAPI} from "./zabbix-api.js";
import {GraphQLError} from "graphql";
export interface ZabbixValue {
itemid?: string,
key?: string,
host?: string,
value: string,
@ -18,13 +21,13 @@ export class ZabbixHistoryGetParams extends ParsedArgs {
time_till_ms: number | undefined
constructor(public itemids: number[] | number | string | string[],
public output: string[] = ["value", "itemid", "clock", "ns"],
public limit: number | null = Array.isArray(itemids) ? itemids.length : 1,
public history: StorageItemType | string = StorageItemType.Text,
time_from?: Date,
time_until?: Date,
public sortfield: string[] = ["clock", "ns"],
public sortorder: SortOrder | null = SortOrder.Desc,
public output: string[] = ["value", "itemid", "clock", "ns"],
public limit: number | null = Array.isArray(itemids) ? itemids.length : 1,
public history: StorageItemType | string = StorageItemType.Text,
time_from?: Date,
time_until?: Date,
public sortfield: string[] = ["clock", "ns"],
public sortorder: SortOrder | null = SortOrder.Desc,
) {
super();
this.time_from_ms = time_from ? Math.floor(new Date(time_from).getTime() / 1000) : undefined
@ -50,3 +53,58 @@ export class ZabbixQueryHistoryRequest extends ZabbixRequest<ZabbixExportValue[]
}
}
}
export interface ZabbixHistoryPushInput {
timestamp: string
value: any,
}
export interface ZabbixHistoryPushResult {
response: string,
data: { itemid: string, error?: string[] | ApiError }[],
error?: ApiError | string[]
}
export class ZabbixHistoryPushParams extends ParsedArgs {
constructor(public values: ZabbixHistoryPushInput[], public itemid?: string,
public key?: string,
public host?: string,) {
super();
}
}
export class ZabbixHistoryPushRequest extends ZabbixRequest<ZabbixHistoryPushResult, ZabbixHistoryPushParams> {
constructor(authToken?: string | null, cookie?: string) {
super("history.push", authToken, cookie);
}
async prepare(zabbixAPI: ZabbixAPI, args?: ZabbixHistoryPushParams): Promise<ZabbixHistoryPushResult | ZabbixErrorResult | undefined> {
if (!args) return undefined;
if (!args.itemid && (!args.key || !args.host)) {
throw new GraphQLError("if itemid is empty both key and host must be filled");
}
return super.prepare(zabbixAPI, args);
}
createZabbixParams(args?: ZabbixHistoryPushParams): ZabbixParams {
if (!args) return [];
return args.values.map(v => {
const date = new Date(v.timestamp);
const result: any = {
value: typeof v.value === 'string' ? v.value : JSON.stringify(v.value),
clock: Math.floor(date.getTime() / 1000),
ns: (date.getTime() % 1000) * 1000000
};
if (args.itemid) {
result.itemid = args.itemid;
} else {
result.host = args.host;
result.key = args.key;
}
return result as ZabbixValue;
});
}
}