diff --git a/api.ts b/api.ts index 7d991cd..d4acbf6 100644 --- a/api.ts +++ b/api.ts @@ -22,9 +22,8 @@ import { createRequestFunction, RequestArgs, CallResult, - PromiseResult, - attributeNames -} from "./common"; + PromiseResult} from "./common"; +import { attributeNames } from "./telemetry"; import { Configuration } from "./configuration"; import { Credentials } from "./credentials"; import { assertParamExists } from "./validation"; diff --git a/common.ts b/common.ts index e2580b4..f5b7c2a 100644 --- a/common.ts +++ b/common.ts @@ -12,12 +12,11 @@ import { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios"; -import { Attributes, metrics } from "@opentelemetry/api"; -import { SEMATTRS_HTTP_HOST, SEMATTRS_HTTP_METHOD, SEMATTRS_HTTP_STATUS_CODE } from "@opentelemetry/semantic-conventions"; +import { metrics } from "@opentelemetry/api"; import { Configuration } from "./configuration"; -import { AuthCredentialsConfig, CredentialsMethod, type Credentials } from "./credentials"; +import type { Credentials } from "./credentials"; import { FgaApiError, FgaApiInternalError, @@ -28,6 +27,7 @@ import { FgaError } from "./errors"; import { setNotEnumerableProperty } from "./utils"; +import { buildAttributes } from "./telemetry"; const meter = metrics.getMeter("@openfga/sdk", "0.5.0"); const durationHist = meter.createHistogram("fga-client.request.duration", { @@ -231,55 +231,3 @@ export const createRequestFunction = function (axiosArgs: RequestArgs, axiosInst }; }; -/** - * Builds an object of attributes that can be used to report alongside an OpenTelemetry metric event. - * - * @param response - The Axios response object, used to add data like HTTP status, host, method, and headers. - * @param credentials - The credentials object, used to add data like the ClientID when using ClientCredentials. - * @param methodAttributes - Extra attributes that the method (i.e. check, listObjects) wishes to have included. Any custom attributes should use the common names. - * @returns {Attributes} - */ -export const buildAttributes = function buildAttributes(response: AxiosResponse|undefined, credentials: AuthCredentialsConfig, methodAttributes: Record = {}): Attributes { - const attributes: Attributes = { - ...methodAttributes, - }; - - if (response?.status) { - attributes[SEMATTRS_HTTP_STATUS_CODE] = response.status; - } - - if (response?.request) { - attributes[SEMATTRS_HTTP_METHOD] = response.request.method; - attributes[SEMATTRS_HTTP_HOST] = response.request.host; - } - - if (response?.headers) { - const modelId = response.headers["openfga-authorization-model-id"]; - if (modelId !== undefined) { - attributes[attributeNames.responseModelId] = modelId; - } - } - - if (credentials?.method === CredentialsMethod.ClientCredentials) { - attributes[attributeNames.requestClientId] = credentials.config.clientId; - } - - return attributes; -}; - -/** - * Common attribute names - */ -export const attributeNames = { - // Attributes associated with the request made - requestModelId: "fga-client.request.model_id", - requestMethod: "fga-client.request.method", - requestStoreId: "fga-client.request.store_id", - requestClientId: "fga-client.request.client_id", - - // Attributes associated with the response - responseModelId: "fga-client.response.model_id", - - // Attributes associated with specific actions - user: "fga-client.user" -}; \ No newline at end of file diff --git a/credentials/credentials.ts b/credentials/credentials.ts index abc96be..8bd4ba6 100644 --- a/credentials/credentials.ts +++ b/credentials/credentials.ts @@ -15,7 +15,8 @@ import globalAxios, { AxiosInstance } from "axios"; import { assertParamExists, isWellFormedUriString } from "../validation"; import { FgaApiAuthenticationError, FgaApiError, FgaError, FgaValidationError } from "../errors"; -import { attemptHttpRequest, buildAttributes } from "../common"; +import { attemptHttpRequest } from "../common"; +import { buildAttributes } from "../telemetry"; import { ApiTokenConfig, AuthCredentialsConfig, ClientCredentialsConfig, CredentialsMethod } from "./types"; import { Counter, metrics } from "@opentelemetry/api"; diff --git a/telemetry.ts b/telemetry.ts new file mode 100644 index 0000000..625e6a6 --- /dev/null +++ b/telemetry.ts @@ -0,0 +1,58 @@ +import { AxiosResponse } from "axios"; +import { Attributes } from "@opentelemetry/api"; +import { SEMATTRS_HTTP_HOST, SEMATTRS_HTTP_METHOD, SEMATTRS_HTTP_STATUS_CODE } from "@opentelemetry/semantic-conventions"; +import { AuthCredentialsConfig, CredentialsMethod } from "./credentials/types"; + +/** + * Builds an object of attributes that can be used to report alongside an OpenTelemetry metric event. + * + * @param response - The Axios response object, used to add data like HTTP status, host, method, and headers. + * @param credentials - The credentials object, used to add data like the ClientID when using ClientCredentials. + * @param methodAttributes - Extra attributes that the method (i.e. check, listObjects) wishes to have included. Any custom attributes should use the common names. + * @returns {Attributes} + */ + +export const buildAttributes = function buildAttributes(response: AxiosResponse | undefined, credentials: AuthCredentialsConfig, methodAttributes: Record = {}): Attributes { + const attributes: Attributes = { + ...methodAttributes, + }; + + if (response?.status) { + attributes[SEMATTRS_HTTP_STATUS_CODE] = response.status; + } + + if (response?.request) { + attributes[SEMATTRS_HTTP_METHOD] = response.request.method; + attributes[SEMATTRS_HTTP_HOST] = response.request.host; + } + + if (response?.headers) { + const modelId = response.headers["openfga-authorization-model-id"]; + if (modelId !== undefined) { + attributes[attributeNames.responseModelId] = modelId; + } + } + + if (credentials?.method === CredentialsMethod.ClientCredentials) { + attributes[attributeNames.requestClientId] = credentials.config.clientId; + } + + return attributes; +}; +/** + * Common attribute names + */ + +export const attributeNames = { + // Attributes associated with the request made + requestModelId: "fga-client.request.model_id", + requestMethod: "fga-client.request.method", + requestStoreId: "fga-client.request.store_id", + requestClientId: "fga-client.request.client_id", + + // Attributes associated with the response + responseModelId: "fga-client.response.model_id", + + // Attributes associated with specific actions + user: "fga-client.user" +};