skyeye-svc-common-utils 0.0.181 → 0.0.185
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -2
- package/src/lib/azureSearch/AzureCognitiveSearchClient.ts +127 -0
- package/src/lib/azureSearch/SearchFilter.ts +126 -0
- package/src/lib/azureSearch/SearchOption.ts +148 -0
- package/src/lib/azureSearch/index.ts +3 -0
- package/src/utils/appConst.ts +21 -0
- package/src/utils/logger/AzureFunctionLogger.ts +27 -0
- package/src/utils/logger/ExpressServerLogger.ts +18 -0
- package/src/utils/logger/LoggerModel.ts +8 -0
- package/src/utils/logger/index.ts +3 -0
- package/src/utils/logger/logger.ts +2 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skyeye-svc-common-utils",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.185",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -21,8 +21,10 @@
|
|
|
21
21
|
},
|
|
22
22
|
"homepage": "https://github.com/HandshakesByDC/SkyEye-SVC-Common-Utils#readme",
|
|
23
23
|
"dependencies": {
|
|
24
|
+
"@azure/functions": "^3.0.0",
|
|
24
25
|
"@azure/identity": "latest",
|
|
25
26
|
"@azure/keyvault-secrets": "latest",
|
|
27
|
+
"@azure/search-documents": "^11.2.1",
|
|
26
28
|
"@azure/service-bus": "^7.1.0",
|
|
27
29
|
"@azure/storage-blob": "^12.1.2",
|
|
28
30
|
"@azure/storage-queue": "^12.0.2",
|
|
@@ -49,7 +51,7 @@
|
|
|
49
51
|
"node-fetch": "^2.6.0",
|
|
50
52
|
"nyc": "^15.1.0",
|
|
51
53
|
"rotating-file-stream": "^1.4.6",
|
|
52
|
-
"skyeye-common-const": "0.0.
|
|
54
|
+
"skyeye-common-const": "0.0.161",
|
|
53
55
|
"swagger-jsdoc": "^3.5.0",
|
|
54
56
|
"swagger-ui-express": "^4.1.3",
|
|
55
57
|
"ts-node": "^9.0.0",
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { SearchClient, AzureKeyCredential } from '@azure/search-documents';
|
|
2
|
+
import { Semaphore } from 'async-mutex';
|
|
3
|
+
import { ServiceResponse } from '../../interfaces/serviceResponse';
|
|
4
|
+
import { azureSearchConf, AzureSearchIndex } from '../../utils/appConst';
|
|
5
|
+
import { LoggerModel, ExpressServerLogger } from '../../utils/logger';
|
|
6
|
+
import { getKey } from '../azure/azureKeyVault';
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* AzureCognitiveSearchClient as an adaptor to bind the third-party library
|
|
11
|
+
* (@azure/search-documents) with the internal application, that is to say, the
|
|
12
|
+
* class is aim to enhance dev's maintenance between lib and the exact usage.
|
|
13
|
+
* @param instance - the class is used as a Singleton
|
|
14
|
+
* @param endpoint - Azure cognitive search's request URL
|
|
15
|
+
* @param credential - Azure cognitive search's API key
|
|
16
|
+
* @param semaphore - to ensure not too many request are sent to Azure cognitive search
|
|
17
|
+
* @param indexMap - to store the index's alias
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* const client = await AzureCognitiveSearchClient.getInstance();
|
|
21
|
+
* const searchOption = new SearchOption( { top: 1 });
|
|
22
|
+
* logger.info(JSON.stringify(await client.query(AzureSearchIndex.company, '*', searchOption.value())));
|
|
23
|
+
*/
|
|
24
|
+
export class AzureCognitiveSearchClient {
|
|
25
|
+
private static instance: AzureCognitiveSearchClient;
|
|
26
|
+
private static endpoint: string;
|
|
27
|
+
private static credential: string;
|
|
28
|
+
private static semaphore: Semaphore;
|
|
29
|
+
private static indexMap: Record<AzureSearchIndex, string>;
|
|
30
|
+
private static logger: LoggerModel;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* To retrieve the instance in the Singleton pattern
|
|
34
|
+
* @returns THE ONLY ONE instance of AzureCognitiveSearchClient
|
|
35
|
+
*/
|
|
36
|
+
static async getInstance(): Promise<AzureCognitiveSearchClient> {
|
|
37
|
+
if (!!AzureCognitiveSearchClient.instance) { return AzureCognitiveSearchClient.instance; }
|
|
38
|
+
AzureCognitiveSearchClient.instance = new AzureCognitiveSearchClient();
|
|
39
|
+
const secret: { endpoint: string, credential: string } = JSON.parse(await getKey(azureSearchConf.key));
|
|
40
|
+
AzureCognitiveSearchClient.indexMap = JSON.parse(await getKey(azureSearchConf.indexKey));
|
|
41
|
+
AzureCognitiveSearchClient.endpoint = secret.endpoint;
|
|
42
|
+
AzureCognitiveSearchClient.credential = secret.credential;
|
|
43
|
+
AzureCognitiveSearchClient.semaphore = new Semaphore(azureSearchConf.semaphoreParallelMaximum);
|
|
44
|
+
|
|
45
|
+
// @default: the default of logger is to use Express Server.
|
|
46
|
+
AzureCognitiveSearchClient.logger = new ExpressServerLogger();
|
|
47
|
+
return AzureCognitiveSearchClient.instance;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
setLogger(logger: LoggerModel) {
|
|
51
|
+
AzureCognitiveSearchClient.logger = logger;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* To query the Azure cognitive search
|
|
56
|
+
* @param index to retrieve the document
|
|
57
|
+
* @param keyword as the prop 'search'
|
|
58
|
+
* @param options additional option for the search
|
|
59
|
+
* @param retryTimes specify how many times if Azure cognitive search returns a bad request
|
|
60
|
+
* @returns ServiceResponse, noted that data is stated in data.document
|
|
61
|
+
*/
|
|
62
|
+
async query(
|
|
63
|
+
index: AzureSearchIndex,
|
|
64
|
+
keyword: string = '*',
|
|
65
|
+
options?: any,
|
|
66
|
+
retryTimes: number = azureSearchConf.queryRetryDefault
|
|
67
|
+
): Promise<ServiceResponse> {
|
|
68
|
+
|
|
69
|
+
AzureCognitiveSearchClient.logger.info('start AzureCognitiveSearchClient/query');
|
|
70
|
+
let serviceResponse: ServiceResponse = { isSuccess: false };
|
|
71
|
+
let searchResults: any;
|
|
72
|
+
try {
|
|
73
|
+
let curRetry = 0;
|
|
74
|
+
|
|
75
|
+
const client = new SearchClient(
|
|
76
|
+
AzureCognitiveSearchClient.endpoint,
|
|
77
|
+
AzureCognitiveSearchClient.indexMap[index],
|
|
78
|
+
new AzureKeyCredential(AzureCognitiveSearchClient.credential)
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
while (curRetry < retryTimes) {
|
|
82
|
+
await AzureCognitiveSearchClient.semaphore.runExclusive(async () => {
|
|
83
|
+
try {
|
|
84
|
+
searchResults = await client.search(keyword, options);
|
|
85
|
+
|
|
86
|
+
serviceResponse.data = { document: [] };
|
|
87
|
+
|
|
88
|
+
for await (const result of searchResults.results) {
|
|
89
|
+
serviceResponse.data.document.push(result.document);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (!!searchResults.facets) {
|
|
93
|
+
serviceResponse.data.facets = searchResults.facets;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (!!searchResults.count) {
|
|
97
|
+
serviceResponse.data.count = searchResults.count;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
serviceResponse.isSuccess = true;
|
|
101
|
+
} catch (err) {
|
|
102
|
+
AzureCognitiveSearchClient.logger.error(`AzureCognitiveSearchClient/query: fail - ${err}`);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
if (!serviceResponse.isSuccess) {
|
|
107
|
+
AzureCognitiveSearchClient.logger.warn(`AzureCognitiveSearchClient/query: retry - ${curRetry}`);
|
|
108
|
+
++curRetry;
|
|
109
|
+
this.sleep(azureSearchConf.retryIntervalSecond * 1000);
|
|
110
|
+
} else {
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
} catch (err) {
|
|
116
|
+
AzureCognitiveSearchClient.logger.error(`AzureCognitiveSearchClient/query: ${err}`);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return serviceResponse;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* To postpone for specific millisecond
|
|
124
|
+
* @param ms - time to wait for
|
|
125
|
+
*/
|
|
126
|
+
private async sleep(ms: number) { await new Promise(_ => setTimeout(_, ms)); }
|
|
127
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SearchFilter is the object to construct the Filter when using Azure cognitive search,
|
|
3
|
+
* @param attr - the attribute, so called props, to be filtered by the condition
|
|
4
|
+
* @param condition - the condition to filter, see enum @SearchFilter for more information
|
|
5
|
+
* @param value - attr should under the condition with value
|
|
6
|
+
*/
|
|
7
|
+
export class SearchFilter {
|
|
8
|
+
attr: string;
|
|
9
|
+
condition: SearchFilterCondition;
|
|
10
|
+
value: any;
|
|
11
|
+
isCollection: boolean = false;
|
|
12
|
+
collectionOperation: 'any' | 'all' = 'any';
|
|
13
|
+
|
|
14
|
+
constructor(
|
|
15
|
+
attr: string,
|
|
16
|
+
condition: SearchFilterCondition,
|
|
17
|
+
value: any,
|
|
18
|
+
isCollection: boolean = false,
|
|
19
|
+
collectionOperation: 'any' | 'all' = 'any') {
|
|
20
|
+
this.attr = attr;
|
|
21
|
+
this.condition = condition;
|
|
22
|
+
this.value = value;
|
|
23
|
+
this.isCollection = isCollection;
|
|
24
|
+
this.collectionOperation = collectionOperation;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* flatten is to compose the instance into a string when using Search
|
|
29
|
+
* @returns the composite of the instance
|
|
30
|
+
*/
|
|
31
|
+
flatten(): string {
|
|
32
|
+
if (this.isCollection) {
|
|
33
|
+
switch (this.condition) {
|
|
34
|
+
case CONTAINS:
|
|
35
|
+
return `${this.attr}/${this.collectionOperation}(i: search.in(i,'${this.value.toString()}', ','))`;
|
|
36
|
+
case EXCLUDE:
|
|
37
|
+
return `${this.attr}/${this.collectionOperation}(i: not search.in(i,'${this.value.toString()}', ','))`;
|
|
38
|
+
default:
|
|
39
|
+
throw new Error(`SearchFilter/flatten: Unknown condition for collection`);
|
|
40
|
+
}
|
|
41
|
+
} else {
|
|
42
|
+
switch (this.condition) {
|
|
43
|
+
case EQUAL:
|
|
44
|
+
case NOT_EQUAL:
|
|
45
|
+
case LESS_THAN_OR_EQUAL:
|
|
46
|
+
case LESS_THAN:
|
|
47
|
+
case GREATER_THAN_OR_EQUAL:
|
|
48
|
+
case GREATER_THAN:
|
|
49
|
+
return `${this.attr} ${this.condition} ${ typeof(this.value) === 'string' ? `'${this.value}'` : this.value }`;
|
|
50
|
+
case CONTAINS:
|
|
51
|
+
return `search.in(${this.attr}, '${this.value.toString()}', ',')`;
|
|
52
|
+
case EXCLUDE:
|
|
53
|
+
return `${this.condition} search.in(${this.attr}, '${this.value.toString()}', ',')`;
|
|
54
|
+
default:
|
|
55
|
+
throw new Error(`SearchFilter/flatten: Unknown condition`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* SearchFilterCondition is equally to the condition when filtering an params.
|
|
63
|
+
*/
|
|
64
|
+
export enum SearchFilterCondition {
|
|
65
|
+
contains = '',
|
|
66
|
+
exclude = 'not',
|
|
67
|
+
equal = 'eq',
|
|
68
|
+
notEqual = 'ne',
|
|
69
|
+
lessThanOrEqual = 'le',
|
|
70
|
+
lessThan = 'lt',
|
|
71
|
+
greaterThanOrEqual = 'ge',
|
|
72
|
+
greaterThan = 'gt'
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* The following const params is a easy-to-use type when implementing a SearchFilter,
|
|
77
|
+
* so that the developers no longer need to call the enum with the class reference
|
|
78
|
+
*/
|
|
79
|
+
export const CONTAINS = SearchFilterCondition.contains;
|
|
80
|
+
export const EXCLUDE = SearchFilterCondition.exclude;
|
|
81
|
+
export const EQUAL = SearchFilterCondition.equal;
|
|
82
|
+
export const NOT_EQUAL = SearchFilterCondition.notEqual;
|
|
83
|
+
export const LESS_THAN_OR_EQUAL = SearchFilterCondition.lessThanOrEqual;
|
|
84
|
+
export const GREATER_THAN_OR_EQUAL = SearchFilterCondition.greaterThanOrEqual;
|
|
85
|
+
export const GREATER_THAN = SearchFilterCondition.greaterThan;
|
|
86
|
+
export const LESS_THAN = SearchFilterCondition.lessThan;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* combination is a function ONLY be used for constructing two function: AND and OR,
|
|
90
|
+
* then it would be express into a string.
|
|
91
|
+
* @param type - to indicate the combination type
|
|
92
|
+
* @param args - the arguments which need to be construct into string
|
|
93
|
+
*/
|
|
94
|
+
const combination = (type: 'and' | 'or', ...args: Array<string | SearchFilter>): string => {
|
|
95
|
+
if (args.length === 0) { return ''; }
|
|
96
|
+
|
|
97
|
+
function flatten(obj: string | SearchFilter): string {
|
|
98
|
+
return typeof(obj) === 'string' ? obj : obj.flatten();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
let res: string = !!args[0] ? flatten(args[0]) : '';
|
|
102
|
+
|
|
103
|
+
for (let i = 1; i < args.length; ++i) {
|
|
104
|
+
if (!!args) {
|
|
105
|
+
res += ` ${type} ${flatten(args[i])}`;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return `(${res})`;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* AND helps developers to compose a nested filter for condition AND.
|
|
114
|
+
* @param args - the arguments which need to be construct into string
|
|
115
|
+
*/
|
|
116
|
+
export const AND = (...args: Array<string | SearchFilter>): string => {
|
|
117
|
+
return combination('and', ...args);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* OR helps developers to compose a nested filter for condition OR.
|
|
122
|
+
* @param args - the arguments which need to be construct into string
|
|
123
|
+
*/
|
|
124
|
+
export const OR = (...args: Array<string | SearchFilter>): string => {
|
|
125
|
+
return combination('or', ...args);
|
|
126
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { AND, SearchFilter } from "./SearchFilter";
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* SearchOptionType is the interface to connect with the library @azure/search-documents,
|
|
6
|
+
* it would only be initiated when creating an instance of class @SearchOption,
|
|
7
|
+
* none of the other functions should access this type declaration.
|
|
8
|
+
* @param select - optional, to indicate the select attributes/props.
|
|
9
|
+
* @param filter - optional, search with the filter
|
|
10
|
+
* @param orderBy - optional, return order
|
|
11
|
+
* @param count - optional, if true, return with the count of the documents.
|
|
12
|
+
* @param top - optional, total volume when retrieving the data
|
|
13
|
+
* @param skip - optional, skip how many document
|
|
14
|
+
* @param facets - optional, retrieve data's facets
|
|
15
|
+
* @param searchMode - required, different mode for search
|
|
16
|
+
*/
|
|
17
|
+
type SearchOptionType = {
|
|
18
|
+
select?: string[],
|
|
19
|
+
filter?: string | Array<string | SearchFilter>,
|
|
20
|
+
orderBy?: SearchOrder[],
|
|
21
|
+
count?: boolean,
|
|
22
|
+
top?: number,
|
|
23
|
+
skip?: number,
|
|
24
|
+
facets?: SearchFacets[],
|
|
25
|
+
searchMode?: SearchMode
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* @classdesc the class is to wrap an option when retrieving the data from
|
|
29
|
+
* @azure/search-documents/query
|
|
30
|
+
* @param searchOptionType - to store the interface of the option, noted that
|
|
31
|
+
* when calling the query, you should use SearchOption.value() instead of using
|
|
32
|
+
* this attribute.
|
|
33
|
+
*/
|
|
34
|
+
export class SearchOption {
|
|
35
|
+
searchOptionType?: SearchOptionType;
|
|
36
|
+
|
|
37
|
+
constructor(searchOptionType?: SearchOptionType) {
|
|
38
|
+
this.searchOptionType = searchOptionType ?? {
|
|
39
|
+
count: false,
|
|
40
|
+
top: 50,
|
|
41
|
+
skip: 0,
|
|
42
|
+
searchMode: SearchMode.all
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* to compose flatten-filter string for @azure/search-documents
|
|
48
|
+
* @returns flatten-filter string
|
|
49
|
+
*/
|
|
50
|
+
private composeFilter(): string {
|
|
51
|
+
if (typeof(this.searchOptionType.filter) === 'string') {
|
|
52
|
+
return this.searchOptionType.filter;
|
|
53
|
+
}
|
|
54
|
+
return AND(...this.searchOptionType.filter);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* to compose flatten-order string for @azure/search-documents
|
|
59
|
+
* @returns flatten-order string
|
|
60
|
+
*/
|
|
61
|
+
private composeOrder(): string[] {
|
|
62
|
+
return this.searchOptionType.orderBy.map(
|
|
63
|
+
(s: SearchOrder) => `${s.attr} ${s.orderBy}`
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* to compose flatten-facets string for @azure/search-documents
|
|
69
|
+
* @returns flatten-facets string
|
|
70
|
+
*/
|
|
71
|
+
private composeFacets(): string[] {
|
|
72
|
+
return this.searchOptionType.facets.map((s: SearchFacets) => {
|
|
73
|
+
let res = `${s.attr},count:${s.count}`;
|
|
74
|
+
if (!!s.sort) { res += `,sort:${s.sort}`; }
|
|
75
|
+
return res;
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* as an adaptor to transform the type for @azure/search-documents
|
|
81
|
+
* @returns object which can be accepted by @azure/search-documents
|
|
82
|
+
*/
|
|
83
|
+
value = () => {
|
|
84
|
+
let value: {
|
|
85
|
+
select?: string[],
|
|
86
|
+
filter?: string;
|
|
87
|
+
orderBy?: string[],
|
|
88
|
+
includeTotalCount?: boolean,
|
|
89
|
+
top?: number,
|
|
90
|
+
skip?: number,
|
|
91
|
+
facets?: string[],
|
|
92
|
+
searchMode?: string,
|
|
93
|
+
} = {};
|
|
94
|
+
|
|
95
|
+
value.includeTotalCount = this.searchOptionType.count;
|
|
96
|
+
value.select = this.searchOptionType.select;
|
|
97
|
+
value.skip = this.searchOptionType.skip;
|
|
98
|
+
value.top = this.searchOptionType.top;
|
|
99
|
+
value.searchMode = this.searchOptionType.searchMode;
|
|
100
|
+
|
|
101
|
+
if (!!this.searchOptionType.filter) {
|
|
102
|
+
value.filter = this.composeFilter();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (!!this.searchOptionType.select && this.searchOptionType.select.length) {
|
|
106
|
+
value.select = this.searchOptionType.select;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (!!this.searchOptionType.orderBy && this.searchOptionType.orderBy.length) {
|
|
110
|
+
value.orderBy = this.composeOrder();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (!!this.searchOptionType.facets && this.searchOptionType.facets.length) {
|
|
114
|
+
value.facets = this.composeFacets();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return value;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* SearchOrder as a type to depict the orderBy props
|
|
123
|
+
* @params attr - the attribute/prop regards to be the target
|
|
124
|
+
* @params orderBy - descent or ascent
|
|
125
|
+
*/
|
|
126
|
+
export type SearchOrder = {
|
|
127
|
+
attr: string;
|
|
128
|
+
orderBy: 'desc' | 'asc';
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* SearchMode is defined by Azure cognitive search
|
|
133
|
+
*/
|
|
134
|
+
export enum SearchMode {
|
|
135
|
+
all = 'all'
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* SearchFacets as a type is to wrap facets for @azure/search-documents
|
|
140
|
+
* @param attr - attribute/prop to reach
|
|
141
|
+
* @param count - volume of the search
|
|
142
|
+
* @param sort - order
|
|
143
|
+
*/
|
|
144
|
+
export type SearchFacets = {
|
|
145
|
+
attr: string;
|
|
146
|
+
count: number;
|
|
147
|
+
sort?: 'count' | '-count' | 'value' | '-value';
|
|
148
|
+
}
|
package/src/utils/appConst.ts
CHANGED
|
@@ -112,4 +112,25 @@ export enum CAMPAIGN_USER_STATUS {
|
|
|
112
112
|
export const exitErrorMessage:Record<string, string> = {
|
|
113
113
|
SQLQueryRunner: `Requests can only be made in the LoggedIn state, not the SentClientRequest state`,
|
|
114
114
|
UnknownTimeout: `operation timed out for an unknown reason`
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export const azureSearchConf = {
|
|
118
|
+
queryRetryDefault: 3,
|
|
119
|
+
semaphoreParallelMaximum: 5,
|
|
120
|
+
retryIntervalSecond: 1,
|
|
121
|
+
key: 'SkyEye-SVC-Search-Credential',
|
|
122
|
+
indexKey: 'SkyEye-SVC-Search-Index'
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export enum AzureSearchIndex {
|
|
126
|
+
news = 'news',
|
|
127
|
+
company = 'company',
|
|
128
|
+
market = 'market',
|
|
129
|
+
financial = 'financial',
|
|
130
|
+
ott = 'ott',
|
|
131
|
+
nerl = 'nerl',
|
|
132
|
+
newNerl = 'newNerl',
|
|
133
|
+
pocNews = 'azure-search-content-poc',
|
|
134
|
+
pocNerl = 'azure-search-nerl-poc',
|
|
135
|
+
pocNewsDuplicate = 'azure-search-contentduplicate-poc'
|
|
115
136
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { LoggerModel } from '.';
|
|
2
|
+
import { Context } from '@azure/functions';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @todo document
|
|
7
|
+
*/
|
|
8
|
+
export class AzureFunctionLogger extends LoggerModel {
|
|
9
|
+
context: Context;
|
|
10
|
+
|
|
11
|
+
constructor(context?: Context) {
|
|
12
|
+
super();
|
|
13
|
+
this.context = context;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
info(content: any) {
|
|
17
|
+
!!content ? this.context.log.info(`${content}`) : console.log(`[info] ${content}`);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
error(content: any) {
|
|
21
|
+
!!content ? this.context.log.error(`${content}`) : console.log(`[error] ${content}`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
warn(content: any) {
|
|
25
|
+
!!content ? this.context.log.warn(`${content}`) : console.log(`[warn] ${content}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import winston from 'winston';
|
|
2
|
+
import { LoggerModel } from '.';
|
|
3
|
+
import { logger as defaultLogger } from '../../utils/logger/logger';
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @todo document
|
|
8
|
+
*/
|
|
9
|
+
export class ExpressServerLogger extends LoggerModel {
|
|
10
|
+
logger: winston.Logger;
|
|
11
|
+
constructor(logger: winston.Logger = defaultLogger) {
|
|
12
|
+
super();
|
|
13
|
+
this.logger = logger;
|
|
14
|
+
}
|
|
15
|
+
info(content: any) { this.logger.info(content); }
|
|
16
|
+
error(content: any) { this.logger.error(content); }
|
|
17
|
+
warn(content: any) { this.logger.warn(content); }
|
|
18
|
+
}
|
|
@@ -22,9 +22,10 @@ export const logger = createLogger({
|
|
|
22
22
|
|
|
23
23
|
// If we're not in production then **ALSO** log to the `console`
|
|
24
24
|
// with the colorized simple format.
|
|
25
|
-
if (commonAppConfig.NodeEnv
|
|
25
|
+
if (commonAppConfig.NodeEnv !== 'production') {
|
|
26
26
|
logger.add(new transports.Console({
|
|
27
27
|
format: format.combine(
|
|
28
|
+
format.colorize(),
|
|
28
29
|
format.simple()
|
|
29
30
|
)
|
|
30
31
|
}));
|