Skip to content
This repository has been archived by the owner on Jul 10, 2023. It is now read-only.

Commit

Permalink
separate lambda related application info logic from index
Browse files Browse the repository at this point in the history
  • Loading branch information
bunyaminsg committed Jun 4, 2020
1 parent 8bff7b4 commit 0b9dff6
Show file tree
Hide file tree
Showing 11 changed files with 190 additions and 113 deletions.
4 changes: 2 additions & 2 deletions src/ThundraWrapper.ts
Expand Up @@ -404,7 +404,7 @@ class ThundraWrapper {
);
}

async executeAfteInvocationAndReport(afterInvocationData: any) {
async executeAfterInvocationAndReport(afterInvocationData: any) {
if (this.monitoringDisabled) {
return;
}
Expand Down Expand Up @@ -442,7 +442,7 @@ class ThundraWrapper {
};
}

await this.executeAfteInvocationAndReport(afterInvocationData);
await this.executeAfterInvocationAndReport(afterInvocationData);

if (this.timeout) {
clearTimeout(this.timeout);
Expand Down
11 changes: 11 additions & 0 deletions src/application/ApplicationInfo.ts
@@ -0,0 +1,11 @@
import ConfigProvider from '../config/ConfigProvider';
import ConfigNames from '../config/ConfigNames';
import ThundraLogger from '../ThundraLogger';

export interface ApplicationInfo {
applicationId: string;
applicationInstanceId: string;
applicationRegion: string;
applicationVersion: string;
applicationTags: any;
}
5 changes: 5 additions & 0 deletions src/application/ApplicationInfoProvider.ts
@@ -0,0 +1,5 @@
import {ApplicationInfo} from './ApplicationInfo';

export interface ApplicationInfoProvider {
getApplicationInfo: () => ApplicationInfo;
}
20 changes: 20 additions & 0 deletions src/application/ApplicationManager.ts
@@ -0,0 +1,20 @@
import {ApplicationInfoProvider} from './ApplicationInfoProvider';
import {LambdaApplicationInfoProvider} from './LambdaApplicationInfoProvider';
import {ApplicationInfo} from './ApplicationInfo';

export class ApplicationManager {

static applicationInfoProvider: ApplicationInfoProvider;

static setApplicationInfoProvider(applicationInfoProvider: ApplicationInfoProvider) {
ApplicationManager.applicationInfoProvider = applicationInfoProvider;
}

static getApplicationInfoProvider(): ApplicationInfoProvider {
return ApplicationManager.applicationInfoProvider;
}

static getApplicationInfo(): ApplicationInfo {
return ApplicationManager.applicationInfoProvider.getApplicationInfo();
}
}
32 changes: 32 additions & 0 deletions src/application/LambdaApplicationInfoProvider.ts
@@ -0,0 +1,32 @@
import Utils from '../plugins/utils/Utils';
import {EnvVariableKeys} from '../Constants';
import {ApplicationInfoProvider} from './ApplicationInfoProvider';
import {ApplicationInfo} from './ApplicationInfo';
import {LambdaContextProvider} from './LambdaContextProvider';
import {LambdaUtils} from '../plugins/utils/LambdaUtils';

export class LambdaApplicationInfoProvider implements ApplicationInfoProvider {

private applicationInfo: ApplicationInfo;

constructor() {
const logStreamName = Utils.getEnvVar(EnvVariableKeys.AWS_LAMBDA_LOG_STREAM_NAME);
const region = Utils.getEnvVar(EnvVariableKeys.AWS_REGION);
const functionVersion = Utils.getEnvVar(EnvVariableKeys.AWS_LAMBDA_FUNCTION_VERSION);
this.applicationInfo = {
applicationId: undefined,
applicationInstanceId: logStreamName ? logStreamName.split(']').pop() : Utils.generateId(),
applicationRegion: region ? region : '',
applicationVersion: functionVersion ? functionVersion : '',
applicationTags: Utils.getApplicationTags(),
};
}

getApplicationInfo(): ApplicationInfo {
const lambdaContext = LambdaContextProvider.getContext();
if (!this.applicationInfo.applicationId && lambdaContext) {
this.applicationInfo.applicationId = LambdaUtils.getApplicationId(lambdaContext);
}
return this.applicationInfo;
}
}
11 changes: 11 additions & 0 deletions src/application/LambdaContextProvider.ts
@@ -0,0 +1,11 @@
export class LambdaContextProvider {
static context: any;

static setContext(context: any) {
LambdaContextProvider.context = context;
}

static getContext() {
return LambdaContextProvider.context;
}
}
44 changes: 21 additions & 23 deletions src/index.ts
Expand Up @@ -18,7 +18,6 @@ import Logger from './plugins/Logger';
import Log from './plugins/Log';
import InvocationSupport from './plugins/support/InvocationSupport';
import InvocationTraceSupport from './plugins/support/InvocationTraceSupport';
import ApplicationSupport from './plugins/support/ApplicationSupport';
import ErrorInjectorSpanListener from './plugins/listeners/ErrorInjectorSpanListener';
import FilteringSpanListener from './plugins/listeners/FilteringSpanListener';
import LatencyInjectorSpanListener from './plugins/listeners/LatencyInjectorSpanListener';
Expand All @@ -33,6 +32,9 @@ import ErrorAwareSampler from './opentracing/sampler/ErrorAwareSampler';
import TimeAwareSampler from './opentracing/sampler/TimeAwareSampler';
import { SamplerCompositionOperator } from './opentracing/sampler/CompositeSampler';
import ConfigNames from './config/ConfigNames';
import {ApplicationManager} from './application/ApplicationManager';
import {LambdaContextProvider} from './application/LambdaContextProvider';
import {LambdaApplicationInfoProvider} from './application/LambdaApplicationInfoProvider';

const ThundraWarmup = require('@thundra/warmup');
const get = require('lodash.get');
Expand Down Expand Up @@ -90,36 +92,32 @@ module.exports = (options?: any) => {
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
}

ApplicationSupport.parseApplicationTags();

const logStreamName = Utils.getEnvVar(EnvVariableKeys.AWS_LAMBDA_LOG_STREAM_NAME);
const region = Utils.getEnvVar(EnvVariableKeys.AWS_REGION);
const functionVersion = Utils.getEnvVar(EnvVariableKeys.AWS_LAMBDA_FUNCTION_VERSION);
const applicationInstanceId = logStreamName ? logStreamName.split(']').pop() : Utils.generateId();

const pluginContext: PluginContext = new PluginContext({
applicationInstanceId,
applicationRegion: region ? region : '',
applicationVersion: functionVersion ? functionVersion : '',
requestCount: 0,
apiKey: config.apiKey,
timeoutMargin: config.timeoutMargin,
transactionId: null,
config,
});

const increaseRequestCount = () => pluginContext.requestCount += 1;

return (originalFunc: any) => {
// Check if already wrapped
if (get(originalFunc, 'thundraWrapped', false)) {
return originalFunc;
}

ApplicationManager.setApplicationInfoProvider(new LambdaApplicationInfoProvider());
const applicationInfoProvider = ApplicationManager.getApplicationInfoProvider();
const applicationInfo = applicationInfoProvider.getApplicationInfo();
const pluginContext: PluginContext = new PluginContext({
applicationInstanceId: applicationInfo.applicationInstanceId,
applicationRegion: applicationInfo.applicationRegion,
applicationVersion: applicationInfo.applicationVersion,
requestCount: 0,
apiKey: config.apiKey,
timeoutMargin: config.timeoutMargin,
transactionId: null,
config,
});

const increaseRequestCount = () => pluginContext.requestCount += 1;

const thundraWrappedHandler: any = async (originalEvent: any, originalContext: any, originalCallback: any) => {
LambdaContextProvider.setContext(originalContext);
// Creating applicationId here, since we need the information in context
const applicationId = Utils.getApplicationId(originalContext, pluginContext);
pluginContext.applicationId = applicationId;
pluginContext.applicationId = ApplicationManager.getApplicationInfo().applicationId;

plugins.forEach((plugin: any) => {
plugin.setPluginContext(pluginContext);
Expand Down
3 changes: 2 additions & 1 deletion src/plugins/Invocation.ts
Expand Up @@ -8,6 +8,7 @@ import MonitoringDataType from './data/base/MonitoringDataType';
import PluginContext from './PluginContext';
import InvocationSupport from './support/InvocationSupport';
import InvocationTraceSupport from './support/InvocationTraceSupport';
import {LambdaUtils} from './utils/LambdaUtils';

class Invocation {
hooks: { 'before-invocation': (data: any) => void; 'after-invocation': (data: any) => void; };
Expand Down Expand Up @@ -78,7 +79,7 @@ class Invocation {

this.invocationData.tags['aws.lambda.memory_limit'] = this.pluginContext.maxMemory;
this.invocationData.tags['aws.lambda.arn'] = originalContext.invokedFunctionArn;
this.invocationData.tags['aws.account_no'] = Utils.getAWSAccountNo(originalContext.invokedFunctionArn);
this.invocationData.tags['aws.account_no'] = LambdaUtils.getAWSAccountNo(originalContext.invokedFunctionArn);
this.invocationData.tags['aws.lambda.invocation.coldstart'] = this.pluginContext.requestCount === 0;
this.invocationData.tags['aws.region'] = this.pluginContext.applicationRegion;
this.invocationData.tags['aws.lambda.log_group_name'] = originalContext ? originalContext.logGroupName : '';
Expand Down
32 changes: 0 additions & 32 deletions src/plugins/support/ApplicationSupport.ts

This file was deleted.

60 changes: 60 additions & 0 deletions src/plugins/utils/LambdaUtils.ts
@@ -0,0 +1,60 @@
import {EnvVariableKeys} from '../../Constants';
import ConfigProvider from '../../config/ConfigProvider';
import ConfigNames from '../../config/ConfigNames';
import Utils from './Utils';

export class LambdaUtils {

static getApplicationId(originalContext: any) {
const arn = originalContext.invokedFunctionArn;
const region = Utils.getEnvVar(EnvVariableKeys.AWS_REGION)
|| 'local';
const accountNo = LambdaUtils.getAccountNo(arn, ConfigProvider.get<string>(ConfigNames.THUNDRA_APIKEY));
const functionName = LambdaUtils.getApplicationName(originalContext);

return `aws:lambda:${region}:${accountNo}:${functionName}`;
}

static getApplicationName(originalContext: any) {
return ConfigProvider.get<string>(ConfigNames.THUNDRA_APPLICATION_NAME,
originalContext.functionName
|| Utils.getEnvVar(EnvVariableKeys.AWS_LAMBDA_FUNCTION_NAME)
|| 'lambda-app');
}

static getAccountNo(arn: string, apiKey: string) {
if (LambdaUtils.getIfSAMLocalDebugging()) {
return 'sam_local';
} else if (LambdaUtils.getIfSLSLocalDebugging()) {
return 'sls_local';
} else {
return (LambdaUtils.getAWSAccountNo(arn)
|| apiKey
|| 'guest');
}
}

static getAWSAccountNo(arn: string) {
return LambdaUtils.getARNPart(arn, 4);
}

static getAWSRegion(arn: string) {
return LambdaUtils.getARNPart(arn, 3);
}

static getARNPart(arn: string, index: number) {
try {
return arn.split(':')[index];
} catch (error) {
return '';
}
}

static getIfSAMLocalDebugging() {
return Utils.getEnvVar(EnvVariableKeys.AWS_SAM_LOCAL) === 'true';
}

static getIfSLSLocalDebugging() {
return Utils.getEnvVar(EnvVariableKeys.SLS_LOCAL) === 'true';
}
}
81 changes: 26 additions & 55 deletions src/plugins/utils/Utils.ts
Expand Up @@ -18,11 +18,11 @@ import MetricData from '../data/metric/MetricData';
import SpanData from '../data/trace/SpanData';
import LogData from '../data/log/LogData';
import ThundraLogger from '../../ThundraLogger';
import ApplicationSupport from '../support/ApplicationSupport';
import ThundraTracer from '../../opentracing/Tracer';
import CompositeMonitoringData from '../data/composite/CompositeMonitoringData';
import InvocationSupport from '../support/InvocationSupport';
import ModuleVersionValidator from '../integrations/ModuleVersionValidator';
import {ApplicationManager} from '../../application/ApplicationManager';

const parse = require('module-details-from-path');
const uuidv4 = require('uuid/v4');
Expand Down Expand Up @@ -381,7 +381,8 @@ class Utils {
monitoringData.applicationVersion = applicationVersion;
monitoringData.applicationRuntimeVersion = process.version;

monitoringData.applicationTags = {...monitoringData.applicationTags, ...ApplicationSupport.applicationTags};
monitoringData.applicationTags = {...monitoringData.applicationTags,
...ApplicationManager.getApplicationInfo().applicationTags};

return monitoringData;
}
Expand Down Expand Up @@ -489,59 +490,6 @@ class Utils {
return monitoringData;
}

static getAWSAccountNo(arn: string) {
return Utils.getARNPart(arn, 4);
}

static getAWSRegion(arn: string) {
return Utils.getARNPart(arn, 3);
}

static getAccountNo(arn: string, pluginContext: any) {
if (Utils.getIfSAMLocalDebugging()) {
return 'sam_local';
} else if (Utils.getIfSLSLocalDebugging()) {
return 'sls_local';
} else {
return (Utils.getAWSAccountNo(arn)
|| pluginContext.apiKey
|| 'guest');
}
}

static getApplicationId(originalContext: any, pluginContext: any) {
const arn = originalContext.invokedFunctionArn;
const region = Utils.getEnvVar(EnvVariableKeys.AWS_REGION)
|| 'local';
const accountNo = Utils.getAccountNo(arn, pluginContext);
const functionName = Utils.getApplicationName(originalContext);

return `aws:lambda:${region}:${accountNo}:${functionName}`;
}

static getApplicationName(originalContext: any) {
return ConfigProvider.get<string>(ConfigNames.THUNDRA_APPLICATION_NAME,
originalContext.functionName
|| Utils.getEnvVar(EnvVariableKeys.AWS_LAMBDA_FUNCTION_NAME)
|| 'lambda-app');
}

static getARNPart(arn: string, index: number) {
try {
return arn.split(':')[index];
} catch (error) {
return '';
}
}

static getIfSAMLocalDebugging() {
return Utils.getEnvVar(EnvVariableKeys.AWS_SAM_LOCAL) === 'true';
}

static getIfSLSLocalDebugging() {
return Utils.getEnvVar(EnvVariableKeys.SLS_LOCAL) === 'true';
}

static getXRayTraceInfo() {
let traceID: string = '';
let segmentID: string = '';
Expand Down Expand Up @@ -593,6 +541,29 @@ class Utils {
return response.statusCode && typeof response.statusCode === 'number';
}

static getApplicationTags(): any {
const applicationTags: any = {};
for (const key of ConfigProvider.names()) {
if (key.startsWith(ConfigNames.THUNDRA_APPLICATION_TAG_PREFIX)) {
try {
const propsKey = key.substring(ConfigNames.THUNDRA_APPLICATION_TAG_PREFIX.length);
const propsValue = ConfigProvider.get<any>(key);
if (isNaN(parseFloat(propsValue))) {
if (propsValue === 'true' || propsValue === 'false') {
applicationTags[propsKey] = propsValue === 'true' ? true : false;
} else {
applicationTags[propsKey] = propsValue;
}
} else {
applicationTags[propsKey] = parseFloat(propsValue);
}
} catch (ex) {
ThundraLogger.getInstance().error(`Cannot parse application tag ${key}`);
}
}
}
return applicationTags;
}
}

export default Utils;

0 comments on commit 0b9dff6

Please sign in to comment.