From be5d816bfb40c72aad990a28c4c69ec0cb8e113c Mon Sep 17 00:00:00 2001 From: yaswanth-pula-skyflow Date: Fri, 19 May 2023 15:41:37 +0530 Subject: [PATCH 1/2] SDK-684 add sdk metrics header in api requests. --- src/service-account/util/Token.ts | 14 ++++++++++---- src/vault-api/client/index.ts | 6 ++++-- src/vault-api/utils/common/index.ts | 4 +++- src/vault-api/utils/helpers/index.ts | 20 +++++++++++++++----- test/vault-api/Client.test.js | 3 ++- 5 files changed, 34 insertions(+), 13 deletions(-) diff --git a/src/service-account/util/Token.ts b/src/service-account/util/Token.ts index b75918b7..5a889e8d 100644 --- a/src/service-account/util/Token.ts +++ b/src/service-account/util/Token.ts @@ -7,8 +7,9 @@ import jwt from "jsonwebtoken"; import { errorMessages } from "../errors/Messages"; import { printLog } from "../../vault-api/utils/logs-helper"; import logs from "../../vault-api/utils/logs"; -import { MessageType } from "../../vault-api/utils/common"; +import { MessageType, SDK_METRICS_HEADER_KEY } from "../../vault-api/utils/common"; import SkyflowError from '../../vault-api/libs/SkyflowError'; +import { generateSDKMetrics } from "../../vault-api/utils/helpers"; export type ResponseToken = { accessToken: string, tokenType: string } export type ResponseSignedDataTokens = { token: string, signedToken: string } @@ -119,7 +120,10 @@ function getToken(credentials, options?: BearerTokenOptions): Promise { - successResponse(res).then((response) => resolve(response)).catch(err => reject(err)) + successResponse(res) + .then((response) => resolve(response)) + .catch((err) => reject(err)); }) .catch((err) => { - failureResponse(err).catch(err => reject(err)) + failureResponse(err).catch((err) => reject(err)); }); } } diff --git a/src/vault-api/client/index.ts b/src/vault-api/client/index.ts index be4d79bd..714c062a 100644 --- a/src/vault-api/client/index.ts +++ b/src/vault-api/client/index.ts @@ -10,10 +10,11 @@ import { } from '../utils/logs-helper'; import { ContentType, - MessageType + MessageType, + SDK_METRICS_HEADER_KEY } from '../utils/common'; import axios, { Method } from 'axios'; -import { objectToFormData, toLowerKeys } from '../utils/helpers'; +import { generateSDKMetrics, objectToFormData, toLowerKeys } from '../utils/helpers'; export interface IClientRequest { body?: any; headers?: Record; @@ -52,6 +53,7 @@ class Client { request = (request: IClientRequest) => new Promise((resolve, reject) => { const headerKeys = toLowerKeys(request.headers); let contentType = headerKeys['content-type'] + headerKeys[SDK_METRICS_HEADER_KEY] = JSON.stringify(generateSDKMetrics()); const data = this.convertRequestBody(request.body,contentType) const headers = this.getHeaders(data,headerKeys) axios({ diff --git a/src/vault-api/utils/common/index.ts b/src/vault-api/utils/common/index.ts index ef7d7c4c..bed77a23 100644 --- a/src/vault-api/utils/common/index.ts +++ b/src/vault-api/utils/common/index.ts @@ -126,4 +126,6 @@ export interface IUpdateInput{ export interface IUpdateOptions{ tokens: boolean -} \ No newline at end of file +} + +export const SDK_METRICS_HEADER_KEY = "sky-metadata"; \ No newline at end of file diff --git a/src/vault-api/utils/helpers/index.ts b/src/vault-api/utils/helpers/index.ts index b70af524..37f5e8ce 100644 --- a/src/vault-api/utils/helpers/index.ts +++ b/src/vault-api/utils/helpers/index.ts @@ -1,11 +1,11 @@ /* Copyright (c) 2022 Skyflow, Inc. */ -import axios from "axios"; -import Client, { IClientRequest } from "../../client"; -import { ContentType, IConnectionConfig } from "../common"; -const qs = require('qs'); -const FormData = require('form-data'); +import * as sdkDetails from "../../../../package.json"; +const FormData = require("form-data"); +const os = require("os"); +const process = require("process"); + export function fillUrlWithPathAndQueryParams(url:string, pathParams?:object, queryParams?:object) { @@ -60,3 +60,13 @@ export function objectToFormData(obj: any, form?: FormData, namespace?: string) return fd; } + + +export const generateSDKMetrics = ()=>{ + return { + "sdk_name_version": `${sdkDetails.name}@${sdkDetails.version}`, + "sdk_client_device_model": `${process.platform} ${process.arch}`, + "sdk_client_os_details": `${os.version()}`, + "sdk_runtime_details": `Node@${process.version}`, + } +}; \ No newline at end of file diff --git a/test/vault-api/Client.test.js b/test/vault-api/Client.test.js index e1d32e2e..29db566c 100644 --- a/test/vault-api/Client.test.js +++ b/test/vault-api/Client.test.js @@ -3,6 +3,7 @@ */ import Client from "../../src/vault-api/client"; import axios from "axios"; +import { generateSDKMetrics } from "../../src/vault-api/utils/helpers"; jest.mock("axios", () => { return { @@ -30,7 +31,7 @@ describe("Client Class",()=>{ headers: { "Content-Type": "application/json" }, }; const data = JSON.stringify({ name: "John Doe", age: 30 }); - const headers = { "content-type": "application/json" }; + const headers = { "content-type": "application/json","sky-metadata":JSON.stringify(generateSDKMetrics()) }; axios.mockImplementation(() => Promise.resolve({ data: { message: "Success" } }) ); From abab5576fb8f7094c3b37df1744c5d736c2d3fd5 Mon Sep 17 00:00:00 2001 From: yaswanth-pula-skyflow Date: Wed, 7 Jun 2023 07:50:21 +0530 Subject: [PATCH 2/2] SK-684 update metrics error cases and testcases --- src/service-account/util/Token.ts | 6 +-- src/vault-api/utils/helpers/index.ts | 63 +++++++++++++++++++++++++--- src/vault-api/utils/logs.ts | 1 + test/vault-api/Util.test.js | 44 ++++++++++++++++++- 4 files changed, 102 insertions(+), 12 deletions(-) diff --git a/src/service-account/util/Token.ts b/src/service-account/util/Token.ts index 5a889e8d..8a242e49 100644 --- a/src/service-account/util/Token.ts +++ b/src/service-account/util/Token.ts @@ -131,12 +131,10 @@ function getToken(credentials, options?: BearerTokenOptions): Promise { - successResponse(res) - .then((response) => resolve(response)) - .catch((err) => reject(err)); + successResponse(res).then((response) => resolve(response)).catch(err => reject(err)) }) .catch((err) => { - failureResponse(err).catch((err) => reject(err)); + failureResponse(err).catch(err => reject(err)) }); } } diff --git a/src/vault-api/utils/helpers/index.ts b/src/vault-api/utils/helpers/index.ts index 37f5e8ce..5c8219ae 100644 --- a/src/vault-api/utils/helpers/index.ts +++ b/src/vault-api/utils/helpers/index.ts @@ -2,6 +2,9 @@ Copyright (c) 2022 Skyflow, Inc. */ import * as sdkDetails from "../../../../package.json"; +import { MessageType } from "../common"; +import logs from "../logs"; +import { parameterizedString, printLog } from "../logs-helper"; const FormData = require("form-data"); const os = require("os"); const process = require("process"); @@ -62,11 +65,59 @@ export function objectToFormData(obj: any, form?: FormData, namespace?: string) } -export const generateSDKMetrics = ()=>{ +export const generateSDKMetrics = () => { + let sdkNameVersion = ""; + let clientDeviceModel = ""; + let clientOSDetails = ""; + let runtimeDetails = ""; + try { + sdkNameVersion = `${sdkDetails.name ? `${sdkDetails.name}@` : ""}${ + sdkDetails.version ? sdkDetails.version : "" + }`; + } catch (err) { + printLog( + parameterizedString(logs.infoLogs.UNABLE_TO_GENERATE_SDK_METRIC,"sdkNameVersion") + ,MessageType.LOG + ); + sdkNameVersion = ""; + } + + try { + clientDeviceModel = `${process.platform ? `${process.platform} ` : ""} ${ + process.arch ? process.arch : "" + }`; + } catch (err) { + printLog( + parameterizedString(logs.infoLogs.UNABLE_TO_GENERATE_SDK_METRIC,"clientDeviceModel") + ,MessageType.LOG + ); + clientDeviceModel = ""; + } + + try { + clientOSDetails = `${os.version() ? os.version() : ""}`; + } catch (err) { + printLog( + parameterizedString(logs.infoLogs.UNABLE_TO_GENERATE_SDK_METRIC,"clientOSDetails") + ,MessageType.LOG + ); + clientOSDetails = ""; + } + + try { + runtimeDetails = `${process.version ? `Node@${process.version}` : ""}`; + } catch (err) { + printLog( + parameterizedString(logs.infoLogs.UNABLE_TO_GENERATE_SDK_METRIC,"runtimeDetails") + ,MessageType.LOG + ); + runtimeDetails = ""; + } + return { - "sdk_name_version": `${sdkDetails.name}@${sdkDetails.version}`, - "sdk_client_device_model": `${process.platform} ${process.arch}`, - "sdk_client_os_details": `${os.version()}`, - "sdk_runtime_details": `Node@${process.version}`, - } + sdk_name_version: sdkNameVersion, + sdk_client_device_model: clientDeviceModel, + sdk_client_os_details: clientOSDetails, + sdk_runtime_details: runtimeDetails, + }; }; \ No newline at end of file diff --git a/src/vault-api/utils/logs.ts b/src/vault-api/utils/logs.ts index c0f7caa0..67e0043a 100644 --- a/src/vault-api/utils/logs.ts +++ b/src/vault-api/utils/logs.ts @@ -35,6 +35,7 @@ const logs = { GENERATE_SIGNED_DATA_TOKENS_TRIGGERED: "generateSignedDataTokens is triggered", UPDATE_TRIGGERED: 'Update method triggered.', UPDATE_REQUEST_RESOLVED:'Update request is resolved.', + UNABLE_TO_GENERATE_SDK_METRIC:'Unable to generate %s1 metric.' }, errorLogs: { diff --git a/test/vault-api/Util.test.js b/test/vault-api/Util.test.js index a8145434..a3a35035 100644 --- a/test/vault-api/Util.test.js +++ b/test/vault-api/Util.test.js @@ -8,9 +8,16 @@ import { import SKYFLOW_ERROR_CODE from "../../src/vault-api/utils/constants"; import { parameterizedString } from "../../src/vault-api/utils/logs-helper"; import SkyflowError from "../../src/vault-api/libs/SkyflowError"; -import { fillUrlWithPathAndQueryParams, formatVaultURL, toLowerKeys, objectToFormData } from "../../src/vault-api/utils/helpers"; +import { fillUrlWithPathAndQueryParams, formatVaultURL, toLowerKeys, objectToFormData, generateSDKMetrics } from "../../src/vault-api/utils/helpers"; const FormData = require('form-data'); +let mockJson = {}; +jest.mock('../../package.json',()=>(mockJson)); +let mockProcess = {}; +jest.mock('process',()=>(mockProcess)); +let mockOS= {}; +jest.mock('os',()=>(mockOS)) + describe("validate upsert options in collect", () => { it("invalid upsert options type", () => { try { @@ -553,4 +560,37 @@ describe("URL helper its", () => { const result = objectToFormData(obj); expect(result).toBeDefined(); }); -}); \ No newline at end of file +}); + +describe("test generateSDKMetrics",()=>{ + + test('should set it empty string when name version are undefined',()=>{ + mockJson = {name:undefined,version:null} + const metrics = generateSDKMetrics(); + expect(metrics.sdk_name_version).toBe(''); + }); + + test('should set it device model empty string when process is invalid or empty',()=>{ + mockProcess = {}; + const metrics = generateSDKMetrics(); + expect(metrics.sdk_client_device_model).toBe(''); + }); + + test('should set it run time details empty string when process is invalid or empty',()=>{ + mockProcess = {}; + const metrics = generateSDKMetrics(); + expect(metrics.sdk_runtime_details).toBe(''); + }); + + test('should set it os details empty string when process is invalid or empty',()=>{ + mockOS = {}; + const metrics = generateSDKMetrics(); + expect(metrics.sdk_client_os_details).toBe(''); + }); + + + + + + +}); \ No newline at end of file