@ti-engine/core 1.1.1 → 1.1.3

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/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # ti-engine changelog
2
2
 
3
+ ## Version 1.1.3
4
+
5
+ * feat(config)!: removed ENV variable `TI_OPERATION_MODE` as it was duplicating the practical purpose of `NODE_ENV`
6
+ * feat(config)!: setting `OPERATION_MODE` is now initialized by the `NODE_ENV` ENV variable (if provided)
7
+ * feat(service instance): show application operation mode in log at successful startup
8
+ * docs: add more sections and information in `README.md`
9
+
10
+ ## Version 1.1.2
11
+
12
+ * feat(localization): add new functionality for localization based on labels and system language. It is currently utilized by the `exceptions` module for localizing the exception descriptions. The new `localization` module can also be accessed externally in the implementing application's files via standard import
13
+ * feat(config): add new setting `localization.labelsPath` that specifies the file path for the localization labels
14
+ * feat(config): add new setting `localization.language` that specifies the language to be used for the labels
15
+ * feat(config): add new ENV variable `TI_LOCALIZATION_LABELS_PATH` that controls the `localization.labelsPath` setting
16
+ * feat(config): add new ENV variable `TI_LOCALIZATION_LANGUAGE` that controls the `localization.language` setting
17
+ * feat(logger): log exception label instead of system-level description
18
+ * fix(start instance): fix the order of ENV loading in the `start-instance.js` script. It will now properly load the `.env` file first and then proceed with any configuration overrides in `config` module
19
+ * fix(service provider): normalize service file paths on dynamic service handler loading
20
+ * build(npm): update npm dependencies to their latest versions
21
+
3
22
  ## Version 1.1.1
4
23
 
5
24
  * feat(config): add new ENV variable `TI_AUDITING_LOG_DETAILS` that controls the `auditing.logDetails` setting
package/README.md CHANGED
@@ -6,10 +6,6 @@ Flexible framework for the creation of microservices with [node.js](https://node
6
6
 
7
7
  The **ti-engine** is an open source, free to use—both for personal and commercial projects—framework for the creation of microservice-based solutions using **node.js**. The architectural concept of the framework is based on a standard _messaging system_ that allows for certain customization but also provides predictability and traceability of its behavior.
8
8
 
9
- Being a messaging system, the **ti-engine** relies on a message broker for the actual exchange of messages between microservice instances. The default implementation of the framework uses [Redis](https://redis.io/) cache, however, you could create your own implementation using something like [Rabbit MQ](https://www.rabbitmq.com/). See the [Advanced topics](#advanced-topics) section of this documentation for guides on how to do this.
10
-
11
- Please be aware, that this framework is under active development and will expand in the near future. Also, this documentation is still in the process of being created and refined. Make sure to keep an eye on the changes in case you want to use it in the meantime.
12
-
13
9
  ## Why ti-engine?
14
10
 
15
11
  The framework is created based on a decade of professional experience with the utilized technologies and architectural approach. It's primary goal is to provide you with a lightweight and flexible solution that can help you build quickly a microservice ecosystem with any degree of size and complexity.
@@ -27,12 +23,19 @@ These are just some benefits **ti-engine** offers. Get to know it better to find
27
23
 
28
24
  ## Prerequisites & installation
29
25
 
26
+ Being a messaging system, the **ti-engine** relies on a message broker for the actual exchange of messages between microservice instances. The default implementation of the framework uses [Redis](https://redis.io/) cache, however, you could create your own implementation using something like [Rabbit MQ](https://www.rabbitmq.com/). See the [Advanced topics](#advanced-topics) section of this documentation for guides on how to do this. For now let's focus on the default setup.
27
+
30
28
  In order to run the basic ti-engine framework you will need a couple of things:
31
29
 
32
30
  * A local [node.js installation](https://nodejs.org/en/download/) with a minimum version of **14.17.0**
33
31
  * A local or remote [Redis cache installation](https://redis.io/download) with a minimum version of **5.0.14**
34
32
 
35
- If you are working under Windows 10+ OS and you need to install Redis, take a look at this [guide](https://redis.com/blog/redis-on-windows-10/). You could also use [Redis Cloud](https://app.redislabs.com/) for development purposes as it offers free basic account.
33
+ If you are working under Windows 10+ OS and you need to install Redis, take a look at this [guide](https://redis.com/blog/redis-on-windows-10/). You could also use [Redis Cloud](https://app.redislabs.com/) for development purposes as it offers free basic account. You can configure your connection to remote Redis server using the following ENV variables:
34
+
35
+ * `TI_MEMORY_CACHE_AUTH_KEY` can be used to provide the Redis password if there is any at all.
36
+ * `TI_MEMORY_CACHE_REDIS_DB` can be used to specify the Redis DB you want to use. Make sure to set the correct number as for example Redis Cloud only uses DB `0`.
37
+ * `TI_MEMORY_CACHE_REDIS_HOST` can be used to provide the remote host. This can be an IP or URL depending on your setup.
38
+ * `TI_MEMORY_CACHE_REDIS_PORT` can be used to provide the remote port. By default, Redis uses `6379` however many implementations might use a custom port that needs to be specified in the connection settings.
36
39
 
37
40
  To get the framework itself, use the command `npm install @ti-engine/core`. And to include it directly in your package.json dependencies execute `npm install @ti-engine/core --save-prod`.
38
41
 
@@ -330,11 +333,132 @@ Now without exiting this node process let's start the original tester microservi
330
333
 
331
334
  This means the service call processing was successful and result was returned to `my-service`. Because we made the receiving of the result blocking and part of the initialization sequence, the new microservice did not report successful startup until it received that response from `ti-tester-service`.
332
335
 
333
- And with this we are ready. The new microservice is now operational. You can continue to tweak and play with it in order to understand better how it all works. For more details on the **ti-engine** inner working please see the following sections.
336
+ And with this step we are done. The new microservice is now operational. You can continue to tweak and play with it in order to understand better how it all works. For more details on the **ti-engine** inner working please see the following sections.
334
337
 
335
338
  ## Using the framework
336
339
 
337
- Under development...
340
+ ### Framework settings
341
+
342
+ Here you can find all settings used by **ti-engine** together with information on what they do. They are defined inside the `config` module and the full list can be accessed through the public `setting` enum. To get the current value of a setting, you can use the public method `getSetting` from the same module. Some settings can be overridden by providing ENV variables as specified below at node application start up.
343
+
344
+ AUDITING_LOG_CONSOLE_ENABLED
345
+ : JSON path `auditing.logConsoleEnabled`, type `boolean`, default `true`
346
+ : ENV variable `TI_AUDITING_LOG_CONSOLE_ENABLED`
347
+ : This setting controls whether the `auditing` module will send the log entries to the OS console or not. In some cases, like Cloud environments, you might want to disable this, especially if the OS console is not made available. This functions independently of other logging outputs like for example GCloud error reporting.
348
+
349
+ AUDITING_LOG_DETAILS
350
+ : JSON path `auditing.logDetails`, type `boolean`, default `true`
351
+ : ENV variable `TI_AUDITING_LOG_DETAILS`
352
+ : This setting controls whether the `auditing` module will include the log entry details (located in the `data` property) in the final log output. You might want to disable this if you want a leaner log output or the log entry details are not something you plan to use for analysis later.
353
+
354
+ AUDITING_LOG_MIN_LEVEL
355
+ : JSON path `auditing.logMinLevel`, type `number`, default `0`
356
+ : ENV variable `TI_AUDITING_LOG_MIN_LEVEL`
357
+ : This setting controls the minimum log severity level that the framework will log in the log output. You can and should set this to `200` (INFO) for production environments in order to filter out the DEBUG and the low-level DEFAULT entries.
358
+
359
+ AUDITING_LOG_USES_JSON
360
+ : JSON path `auditing.logUsesJSON`, type `boolean`, default `false`
361
+ : ENV variable `TI_AUDITING_LOG_USES_JSON`
362
+ : This setting controls whether the log entries would be sent to output formatted as JSONs or not. By default, the framework outputs log entries as prettified text. In some cases however you might want to have the entire entry as a JSON for further processing (for example if you're sending all logs to Elasticsearch).
363
+
364
+ GCLOUD_API_KEY (Alpha)
365
+ : JSON path `gcloudIntegration.apiKey`
366
+ : This setting holds the API key for the GCloud integration module.
367
+
368
+ GCLOUD_PROJECT_ID (Alpha)
369
+ : JSON path `gcloudIntegration.projectID`
370
+ : This setting holds the project ID for the GCloud integration module.
371
+
372
+ LOCALIZATION_LABELS_PATH
373
+ : JSON path `localization.labelsPath`, type `string`, default `../core/bin/localization/labels.json`
374
+ : ENV variable `TI_LOCALIZATION_LABELS_PATH`
375
+ : This setting holds the file system path to the `.json` file containing the localization information. By default, the framework provides such a file with english texts that can be customized further. Alternatively, you can provide your own file from a different location, but it still has to follow the rules of the `localization` module.
376
+
377
+ LOCALIZATION_LANGUAGE
378
+ : JSON path `localization.language`, type `string`, default `en`
379
+ : ENV variable `TI_LOCALIZATION_LANGUAGE`
380
+ : This setting specifies the default framework language. It will be used when translating labels into a localized text.
381
+
382
+ MEMORY_CACHE_AUTH_KEY
383
+ : JSON path `memoryCache.authKey`, type `string`, default `undefined`
384
+ : ENV variable `TI_MEMORY_CACHE_AUTH_KEY`
385
+ : This setting holds the Redis password for accessing the Redis server if such password is required.
386
+
387
+ MEMORY_CACHE_REDIS_DB
388
+ : JSON path `memoryCache.redisDB`, type `number`, default `0`
389
+ : ENV variable `TI_MEMORY_CACHE_REDIS_DB`
390
+ : This setting specifies the Redis DB to be used for all operations. When setting this make sure that the Redis server actually supports multiple DBs (for example Redis Cloud has only one DB with ID `0`).
391
+
392
+ MEMORY_CACHE_REDIS_HOST
393
+ : JSON path `memoryCache.redisHost`, type `string`, default `127.0.0.1`
394
+ : ENV variable `TI_MEMORY_CACHE_REDIS_HOST`
395
+ : This setting holds the Redis server hostname. It can be an IP or URL depending on your configuration.
396
+
397
+ MEMORY_CACHE_REDIS_PORT
398
+ : JSON path `memoryCache.redisPort`, type `number`, default `6379`
399
+ : ENV variable `TI_MEMORY_CACHE_REDIS_PORT`
400
+ : This setting holds the Redis server port.
401
+
402
+ MEMORY_CACHE_USER
403
+ : JSON path `memoryCache.user`, type `string`, default `default`
404
+ : ENV variable `TI_MEMORY_CACHE_USER`
405
+ : This setting holds the Redis username for accessing the Redis server if this is supported by the Redis version (it will be ignored otherwise).
406
+
407
+ MESSAGE_EXCHANGE_QUEUE_PREFIX (Advanced)
408
+ : JSON path `messageExchange.messageQueuePrefix`, type `string`, default `ti:messages:`
409
+ : This setting holds the Redis key prefix for the queues that will hold the messages of the message exchange. This is not something you should modify unless you are making a customized implementation of the tier 1 architectural layer.
410
+
411
+ MESSAGE_EXCHANGE_MESSAGE_STORE (Advanced)
412
+ : JSON path `messageExchange.messageStore`, type `string`, default `ti:messages:store`
413
+ : This setting holds the Redis key name of the hash table that will hold the message payloads of the message exchange. This is not something you should modify unless you are making a customized implementation of the tier 1 architectural layer.
414
+
415
+ MESSAGE_EXCHANGE_SECURITY_HASH_ENABLED (Advanced)
416
+ : JSON path `messageExchange.securityHashEnabled`, type `boolean`, default `true`
417
+ : ENV variable `TI_MESSAGE_EXCHANGE_SECURITY_HASH_ENABLED`
418
+ : This setting controls whether the message exchange will use a control hash mechanism to ensure there is no tampering with the messages in between service calls. In most cases you would want to keep this enabled since it ensures the integrity of your data. If you are concerned about performance (hashing with `blake2` is very fast, but it still eats some milliseconds) you might want to try and disable this to see if it makes any notable difference.
419
+
420
+ MESSAGE_EXCHANGE_SECURITY_HASH_KEY (Advanced)
421
+ : JSON path `messageExchange.securityHashKey`, type `string`, default `random uuid`
422
+ : ENV variable `TI_MESSAGE_EXCHANGE_SECURITY_HASH_KEY`
423
+ : This setting holds the encryption key used by the message exchange control hash mechanism. By default, this has a random uuid value that can be used for development purposes only. For production environments you absolutely must provide your own encryption key via the ENV variable. Depending on your configuration and infrastructure it might come from a secure storage, HSM, key vault, etc.
424
+
425
+ MESSAGE_EXCHANGE_TRACE_EXPIRATION_TIME
426
+ : JSON path `messageExchange.traceExpirationTime`, type `number`, default `3600`
427
+ : This setting specifies the expiration time in seconds of the Redis key that will hold the message trace entries. Set this to `0` to disable expiration altogether.
428
+
429
+ MESSAGE_EXCHANGE_TRACE_LOG_ENABLED
430
+ : JSON path `messageExchange.traceLogEnabled`, type `boolean`, default `false`
431
+ : ENV variable `TI_MESSAGE_EXCHANGE_TRACE_LOG_ENABLED`
432
+ : This setting controls whether the `auditing` module should output all trace messages as normal log entries or not. Normally, you don't want that since it will clutter the standard log quite a lot. All traces go their own storage and can be reviewed and processed separately from the log entries. In some cases, however, as in debugging, enabling this can help you identify hard to track problem.
433
+
434
+ MESSAGE_EXCHANGE_TRACE_REPOSITORY (Advanced)
435
+ : JSON path `messageExchange.traceRepository`, type `string`, default `ti:messages:trace`
436
+ : This setting holds the Redis key name for the message trace cache storage. This is not something you should modify unless you are making a customized implementation of the tier 1 architectural layer.
437
+
438
+ SERVICE_EXECUTION_TIMEOUT
439
+ : JSON path `serviceConfig.executionTimeout`, type `number`, default `180000`
440
+ : This setting specifies the timeout in milliseconds of the service call executions at tier 2 of the architecture. Any service call that hasn't received response within this time will interrupt the wait and raise an `E_COM_SERVICE_EXEC_TIMEOUT` exception. Please keep in mind that reaching the timeout does not mean the remote service did not process the request. You might want to tweak this setting if you have many time-consuming operations in business services, or you plan to integrate with slow APIs.
441
+
442
+ SERVICE_HEALTH_CHECK_ADDRESS (Advanced)
443
+ : JSON path `serviceConfig.healthCheckAddress`, type `string`, default `ti:services:registry:health:`
444
+ : This setting specifies the address of the health check report endpoint for the microservice. In the default implementation this is a prefix for a Redis key that gets updated once at every `SERVICE_HEALTH_CHECK_INTERVAL`. If you override the `reportHealthy` method of the microservice, this setting can contain a URL or another type of destination that can be used by your custom implementation.
445
+
446
+ SERVICE_HEALTH_CHECK_INTERVAL (Advanced)
447
+ : JSON path `serviceConfig.healthCheckInterval`, type `CRON string`, default `*/1 * * * * *`
448
+ : This setting specifies the health check report interval at which the endpoint in `SERVICE_HEALTH_CHECK_ADDRESS` is notified.
449
+
450
+ SERVICE_HEALTH_CHECK_TIMEOUT (Advanced)
451
+ : JSON path `serviceConfig.healthCheckTimeout`, type `number`, default `3`
452
+ : This setting specifies the timeout in seconds after which a microservice is no longer considered healthy. In the default implementation this represents an expiration parameter to the Redis key defined in `SERVICE_HEALTH_CHECK_ADDRESS`. Essentially, if the microservice does not update the Redis key within this time interval, it will expire and the monitoring application will lose the healthy status of the microservice. If you override the `reportHealthy` method of the microservice, this setting can be used for your custom implementation as needed.
453
+
454
+ SERVICE_REGISTRY_ADDRESS (Advanced)
455
+ : JSON path `serviceConfig.serviceRegistryAddress`, type `string`, default `ti:services:registry:catalog:`
456
+ : This setting holds the prefix of the Redis key name used as business service registry. If the microservice is a `ServiceProvider`, on start up it will register its business service portfolio in that Redis set. Also, on each service call that same registry will be searched for the existence of the called business service. This is not something you should modify unless you are making a customized implementation of the tier 1 architectural layer.
457
+
458
+ OPERATION_MODE
459
+ : JSON path `operationMode`, type `string`, default `production`
460
+ : ENV variable `NODE_ENV`
461
+ : This setting holds the current operation mode of the node application. It will inherit the value from the `NODE_ENV` variable if it exists, otherwise will use its default.
338
462
 
339
463
  ## Advanced topics
340
464
 
@@ -0,0 +1,65 @@
1
+ {
2
+ "labels": {
3
+ "general": {
4
+ "exceptions": {
5
+ "0": {
6
+ "en": "Unidentified error encountered or unrecognized exception code provided."
7
+ },
8
+ "1000": {
9
+ "en": "Error thrown by internal JS source."
10
+ },
11
+ "1001": {
12
+ "en": "Attempt to construct an abstract class detected."
13
+ },
14
+ "1002": {
15
+ "en": "Attempt to call an abstract method detected."
16
+ },
17
+ "1003": {
18
+ "en": "Invalid or no service domain name provided at microservice startup."
19
+ },
20
+ "1004": {
21
+ "en": "The system cache required for proper engine operation is unavailable."
22
+ },
23
+ "1005": {
24
+ "en": "The provided service handler is not a proper function."
25
+ },
26
+ "1006": {
27
+ "en": "The requested feature is not supported by current configuration or version."
28
+ },
29
+ "2000": {
30
+ "en": "Invalid authorization token provided."
31
+ },
32
+ "2001": {
33
+ "en": "Invalid or expired session encountered."
34
+ },
35
+ "2002": {
36
+ "en": "Attempt for unauthorized access detected."
37
+ },
38
+ "2003": {
39
+ "en": "The system detected tampering with the message received via message exchange."
40
+ },
41
+ "3000": {
42
+ "en": "General error during cross-application communication."
43
+ },
44
+ "3001": {
45
+ "en": "The message sender instance is currently unavailable."
46
+ },
47
+ "3002": {
48
+ "en": "The execution of a service could not complete within the allowed timeout."
49
+ },
50
+ "3003": {
51
+ "en": "The specified service is not found in the service registry."
52
+ },
53
+ "3004": {
54
+ "en": "The specified service is not found in the service definition interface."
55
+ },
56
+ "3005": {
57
+ "en": "No handler found in the interface for the specified service or service version."
58
+ },
59
+ "3010": {
60
+ "en": "Connection retry attempts exceeded the configured limit."
61
+ }
62
+ }
63
+ }
64
+ }
65
+ }
package/bin/settings.json CHANGED
@@ -11,6 +11,10 @@
11
11
  "logName": "ti-engine",
12
12
  "projectID": ""
13
13
  },
14
+ "localization": {
15
+ "labelsPath": "../core/bin/localization/labels.json",
16
+ "language": "en"
17
+ },
14
18
  "memoryCache": {
15
19
  "authKey": null,
16
20
  "redisDB": 0,
@@ -7,12 +7,13 @@
7
7
 
8
8
  const _ = require( "lodash" );
9
9
  const path = require( "path" );
10
- const tools = require( "#tools" );
11
- const logger = require( "#logger" );
12
10
 
13
- // load any ENV variables defined in a .env file:
11
+ // load any ENV variables defined in a .env file - before including any framework files:
14
12
  require( "dotenv" ).config( { path: path.join( process.cwd(), ".env" ) } );
15
13
 
14
+ const tools = require( "#tools" );
15
+ const logger = require( "#logger" );
16
+
16
17
  // configure the current instance variables before requiring any platform modules and store the necessary ones in memory cache:
17
18
  process.env.TI_INSTANCE_ID = "ti-" + tools.getUUID();
18
19
  process.env.TI_INSTANCE_CLASS = process.env.TI_INSTANCE_CLASS || "";
@@ -74,13 +75,14 @@ process.on( "uncaughtException", ( error ) => {
74
75
  try {
75
76
  logger.log( `Starting new instance of type '${ process.env.TI_INSTANCE_NAME }' with instance ID '${ process.env.TI_INSTANCE_ID }'.`, logger.logSeverity.NOTICE );
76
77
 
77
- /** @type ServiceInstance */
78
78
  const serviceConstructor = require( path.join( process.cwd(), process.env.TI_INSTANCE_CLASS ) );
79
79
  const serviceConfigPath = process.env.TI_INSTANCE_CONFIG;
80
+ /** @type ServiceConfiguration */
80
81
  let serviceConfig = {};
81
82
  if ( serviceConfigPath ) {
82
83
  serviceConfig = require( path.join( process.cwd(), process.env.TI_INSTANCE_CONFIG ) );
83
84
  }
85
+ /** @type ServiceInstance */
84
86
  const mainInstance = new serviceConstructor( process.env.TI_INSTANCE_NAME, serviceConfig );
85
87
 
86
88
  /** @override */
@@ -225,7 +225,8 @@ class ServiceInstance {
225
225
  } );
226
226
 
227
227
  logger.log( `Instance '${ ServiceInstance.instanceID }' started successfully.`, logger.logSeverity.NOTICE, {
228
- nodeVersion: process.version
228
+ nodeVersion: process.version,
229
+ operationMode: config.getSetting( config.setting.OPERATION_MODE )
229
230
  } );
230
231
 
231
232
  resolve();
@@ -138,7 +138,7 @@ class ServiceProvider extends ServiceConsumer {
138
138
  /** @type {ServiceHandlerMethod} */
139
139
  let serviceHandler = null;
140
140
  if ( serviceDefinition.serviceFile ) {
141
- let serviceFilePath = path.join( process.cwd(), serviceDefinition.serviceFile );
141
+ let serviceFilePath = path.normalize( path.join( process.cwd(), serviceDefinition.serviceFile ) );
142
142
  try {
143
143
  serviceHandler = require( serviceFilePath ).service;
144
144
  } catch ( error ) {
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@ti-engine/core",
3
- "version": "1.1.1",
3
+ "version": "1.1.3",
4
4
  "description": "The ti-engine is an open source, free to use—both for personal and commercial projects—framework for the creation of microservice-based solutions using node.js.",
5
5
  "author": "Boris Kostadinov <kostadinov.boris@gmail.com>",
6
6
  "license": "ISC",
7
7
  "exports": {
8
8
  "./exceptions": "./utils/exceptions.js",
9
+ "./localization": "./utils/localization.js",
9
10
  "./logger": "./utils/logger.js",
10
11
  "./service-consumer": "./components/service-consumer.js",
11
12
  "./service-instance": "./components/service-instance.js",
@@ -22,6 +23,7 @@
22
23
  "#default-message-sender": "./components/exchange/default/default-message-sender.js",
23
24
  "#exceptions": "./utils/exceptions.js",
24
25
  "#gcloud-integration": "./integrations/gcloud-integration.js",
26
+ "#localization": "./utils/localization.js",
25
27
  "#logger": "./utils/logger.js",
26
28
  "#message-dispatcher": "./components/exchange/message-dispatcher.js",
27
29
  "#message-exchange": "./components/exchange/message-exchange.js",
@@ -43,7 +45,7 @@
43
45
  "dependencies": {
44
46
  "blake2": "^5.0.0",
45
47
  "dotenv": "^16.3.1",
46
- "fs-extra": "^11.1.1",
48
+ "fs-extra": "^11.2.0",
47
49
  "lodash": "^4.17.21",
48
50
  "node-schedule": "^2.1.1",
49
51
  "ioredis": "^5.3.2"
@@ -54,7 +56,7 @@
54
56
  },
55
57
  "repository": {
56
58
  "type": "git",
57
- "url": "https://github.com/Belleal/ti-engine.git"
59
+ "url": "git+https://github.com/Belleal/ti-engine.git"
58
60
  },
59
61
  "engines": {
60
62
  "node": ">=14.17.0"
package/utils/config.js CHANGED
@@ -24,6 +24,8 @@ const tools = require( "#tools" );
24
24
  * @property {EnvironmentVariable} env.TI_AUDITING_LOG_DETAILS
25
25
  * @property {EnvironmentVariable} env.TI_AUDITING_LOG_MIN_LEVEL
26
26
  * @property {EnvironmentVariable} env.TI_AUDITING_LOG_USES_JSON
27
+ * @property {EnvironmentVariable} env.TI_LOCALIZATION_LABELS_PATH
28
+ * @property {EnvironmentVariable} env.TI_LOCALIZATION_LANGUAGE
27
29
  * @property {EnvironmentVariable} env.TI_MEMORY_CACHE_AUTH_KEY
28
30
  * @property {EnvironmentVariable} env.TI_MEMORY_CACHE_REDIS_DB
29
31
  * @property {EnvironmentVariable} env.TI_MEMORY_CACHE_REDIS_HOST
@@ -32,7 +34,6 @@ const tools = require( "#tools" );
32
34
  * @property {EnvironmentVariable} env.TI_MESSAGE_EXCHANGE_SECURITY_HASH_ENABLED
33
35
  * @property {EnvironmentVariable} env.TI_MESSAGE_EXCHANGE_SECURITY_HASH_KEY
34
36
  * @property {EnvironmentVariable} env.TI_MESSAGE_EXCHANGE_TRACE_LOG_ENABLED
35
- * @property {EnvironmentVariable} env.TI_OPERATION_MODE
36
37
  */
37
38
 
38
39
  /**
@@ -43,6 +44,7 @@ const tools = require( "#tools" );
43
44
  * @typedef {Object} SettingsMain
44
45
  * @property {SettingsAuditing} auditing
45
46
  * @property {SettingsGcloudIntegration} gcloudIntegration
47
+ * @property {SettingsLocalization} localization
46
48
  * @property {SettingsMemoryCache} memoryCache
47
49
  * @property {SettingsMessageExchange} messageExchange
48
50
  * @property {SettingsServiceConfig} serviceConfig
@@ -63,6 +65,12 @@ const tools = require( "#tools" );
63
65
  * @property {string} projectID
64
66
  */
65
67
 
68
+ /**
69
+ * @typedef {Object} SettingsLocalization
70
+ * @property {string} labelsPath
71
+ * @property {string} language
72
+ */
73
+
66
74
  /**
67
75
  * @typedef {Object} SettingsMemoryCache
68
76
  * @property {string} authKey
@@ -105,6 +113,8 @@ let settingsEnum = tools.enum( {
105
113
  AUDITING_LOG_USES_JSON: [ "auditing.logUsesJSON", "logUsesJSON", "" ],
106
114
  GCLOUD_API_KEY: [ "gcloudIntegration.apiKey", "apiKey", "" ],
107
115
  GCLOUD_PROJECT_ID: [ "gcloudIntegration.projectID", "projectID", "" ],
116
+ LOCALIZATION_LABELS_PATH: [ "localization.labelsPath", "labelsPath", "" ],
117
+ LOCALIZATION_LANGUAGE: [ "localization.language", "language", "" ],
108
118
  MEMORY_CACHE_AUTH_KEY: [ "memoryCache.authKey", "authKey", "" ],
109
119
  MEMORY_CACHE_REDIS_DB: [ "memoryCache.redisDB", "redisDB", "" ],
110
120
  MEMORY_CACHE_REDIS_HOST: [ "memoryCache.redisHost", "redisHost", "" ],
@@ -140,6 +150,10 @@ if ( settings.auditing ) {
140
150
  settings.auditing.logMinLevel = ( process.env.TI_AUDITING_LOG_MIN_LEVEL !== undefined ) ? process.env.TI_AUDITING_LOG_MIN_LEVEL : settings.auditing.logMinLevel;
141
151
  settings.auditing.logUsesJSON = ( process.env.TI_AUDITING_LOG_USES_JSON !== undefined ) ? tools.toBool( process.env.TI_AUDITING_LOG_USES_JSON ) : settings.auditing.logUsesJSON;
142
152
  }
153
+ if ( settings.localization ) {
154
+ settings.localization.labelsPath = ( process.env.TI_LOCALIZATION_LABELS_PATH !== undefined ) ? process.env.TI_LOCALIZATION_LABELS_PATH : settings.localization.labelsPath;
155
+ settings.localization.language = ( process.env.TI_LOCALIZATION_LANGUAGE !== undefined ) ? process.env.TI_LOCALIZATION_LANGUAGE : settings.localization.language;
156
+ }
143
157
  if ( settings.memoryCache ) {
144
158
  settings.memoryCache.authKey = ( process.env.TI_MEMORY_CACHE_AUTH_KEY !== undefined ) ? process.env.TI_MEMORY_CACHE_AUTH_KEY : settings.memoryCache.authKey;
145
159
  settings.memoryCache.redisDB = ( process.env.TI_MEMORY_CACHE_REDIS_DB !== undefined ) ? process.env.TI_MEMORY_CACHE_REDIS_DB : settings.memoryCache.redisDB;
@@ -159,7 +173,7 @@ if ( process.env.TI_GCLOUD_ENABLED === true && settings.gcloudIntegration ) {
159
173
  settings.gcloudIntegration.projectID = ( process.env.TI_GCLOUD_PROJECT_ID !== undefined ) ? process.env.TI_GCLOUD_PROJECT_ID : settings.gcloudIntegration.projectID;
160
174
  }
161
175
 
162
- settings.operationMode = process.env.TI_OPERATION_MODE || settings.operationMode;
176
+ settings.operationMode = process.env.NODE_ENV || settings.operationMode;
163
177
 
164
178
  // prevent further modifications to the settings object:
165
179
  Object.freeze( settings );
@@ -0,0 +1,27 @@
1
+ /*
2
+ * SPDX-FileCopyrightText: © 2021-2023 Boris Kostadinov <kostadinov.boris@gmail.com>
3
+ * SPDX-License-Identifier: ICU
4
+ */
5
+
6
+ const _ = require( "lodash" );
7
+ const path = require( "path" );
8
+ const config = require( "#config" );
9
+
10
+ const labelsPath = path.normalize( path.join( process.cwd(), config.getSetting( config.setting.LOCALIZATION_LABELS_PATH ) ) );
11
+ const labels = require( labelsPath );
12
+ const defaultEmptyLabel = "!!! label not found !!!";
13
+
14
+ // prevent further modifications to the labels object:
15
+ Object.freeze( labels );
16
+
17
+ /**
18
+ * Used to return the textual value for a label based on the current system language.
19
+ *
20
+ * @method
21
+ * @param {string} label This should be a dot-separated JSON path string.
22
+ * @returns {string}
23
+ * @public
24
+ */
25
+ module.exports.getLabel = ( label ) => {
26
+ return _.get( labels, label + "." + config.getSetting( config.setting.LOCALIZATION_LANGUAGE ), defaultEmptyLabel );
27
+ };
package/utils/logger.js CHANGED
@@ -6,6 +6,7 @@
6
6
  const _ = require( "lodash" );
7
7
  const tools = require( "#tools" );
8
8
  const exceptions = require( "#exceptions" );
9
+ const localization = require( "#localization" );
9
10
 
10
11
  /**
11
12
  * Enum for specifying the log entry severity. This is based on the Google Stackdriver severity levels.
@@ -52,7 +53,7 @@ module.exports.getSeverityName = ( severity ) => {
52
53
  const exceptionToLog = ( exception ) => {
53
54
  return {
54
55
  exceptionID: exception.id,
55
- description: exception.description,
56
+ description: localization.getLabel( exception.label ),
56
57
  details: !_.isEmpty( exception.data ) ? exception.data : undefined
57
58
  };
58
59
  };