Adding logging to a component
Key takeaways
Logging | Logging is the capacity to create tagged messages from events in our code. |
Logging levels | Logging levels: nothing, fatal, error, warn, info, debug, and trace. |
ConsoleLogger | PIP.Services component for displaying logging messages on the console. |
CachedLogger | PIP.Services component that caches log messages in memory. |
CompositeLogger | PIP.Services component for aggregating logging messages. |
DataDogLogger, ElasticSearchLogger, CloudWatchLogger | PIP.Services logger implementations for Datadog, Elasticsearch, and Amazon CloudWatch components. |
Introduction
In this tutorial, you will learn how to add logging capacity to a microservice. First, we will understand what logging consists of. Then, we will use the microservice we created in the “Creating a component” tutorial, replace the printed messages with logger messages and create an exception in our business process (my_task). After running the code, we will see the tagged messages from the logger.
Once we have seen how to create a logger that displays messages on our console, we will learn how to create a composite logger, which will add the capacity to aggregate the log messages from different sources and centralize their display on our console.
Finally, we will see how to add loggers for Datadog, Elasticsearch, and Amazon CloudWatch components.
What is logging?
Logging is the capacity to create tagged messages from events in our code. These messages can inform us about the running process.
There are different logging levels. PIP.Services defines them as:
Level name | Level number | Description |
---|---|---|
Nothing | 0 | Nothing to be logged. |
Fatal | 1 | Logs only fatal errors that cause a microservice to fail. |
Error | 2 | Logs all errors - fatal or recoverable. |
Warn | 3 | Logs errors and warnings. |
Info | 4 | Logs errors and important information messages. |
Debug | 5 | Logs everything up to high-level debugging information. |
Trace | 6 | Logs everything down to fine-granular debugging messages. |
Once generated, log messages need to be stored or displayed. PIP.Services provides specific tools for this: CachedLogger and ConsoleLogger. The first class stores log messages in memory. The second class displays them on a console. The toolkit also provides us with the CompositeLogger, which allows for message aggregation and thus, creating a centralized logging point.
Additionally, PIP.Services provides implementations of loggers for CloudWatch, ElasticSearch, and DataDog.
Once generated, log messages need to be stored or displayed. PIP.Services provides specific tools for this: CachedLogger and ConsoleLogger. The first class stores log messages in memory. The second class displays them on a console. The toolkit also provides us with the CompositeLogger, which allows for message aggregation and thus, creating a centralized logging point.
Additionally, PIP.Services provides implementations of loggers for CloudWatch, ElasticSearch, and DataDog.
Once generated, log messages need to be stored or displayed. PIP.Services provides specific tools for this: CachedLogger and ConsoleLogger. The first class stores log messages in memory. The second class displays them on a console. The toolkit also provides us with the CompositeLogger, which allows for message aggregation and thus, creating a centralized logging point.
Additionally, PIP.Services provides implementations of loggers for CloudWatch, ElasticSearch, and DataDog.
Once generated, log messages need to be stored or displayed. PIP.Services provides specific tools for this: CachedLogger and ConsoleLogger. The first class stores log messages in memory. The second class displays them on a console. The toolkit also provides us with the CompositeLogger, which allows for message aggregation and thus, creating a centralized logging point.
Additionally, PIP.Services provides implementations of loggers for CloudWatch, ElasticSearch, and DataDog.
Once generated, log messages need to be stored or displayed. PIP.Services provides specific tools for this: CachedLogger and ConsoleLogger. The first class stores log messages in memory. The second class displays them on a console. The toolkit also provides us with the CompositeLogger, which allows for message aggregation and thus, creating a centralized logging point.
Additionally, PIP.Services provides implementations of loggers for CloudWatch, ElasticSearch, and DataDog.
Now, we will see how to create a console logger and a composite logger.
Adding a console logger to our component
In our example, we will add a logger that sends messages to our console. For this, we will use the ConsoleLogger class. After we created an instance of this class, we will set the logging level to five, which will allow us to log everything up to debug level.
var logger = new ConsoleLogger();
logger.setLevel(5);
// Logger setting
var logger = new ConsoleLogger();
logger.Level = LogLevel.Debug;
// Logger setting
logger := *clog.NewConsoleLogger()
logger.SetLevel(5)
var logger = ConsoleLogger();
logger.setLevel(LogLevel.Debug);
# Logger setting
logger = ConsoleLogger()
logger.set_level(5)
Then, we will replace our print messages with info-level log messages. For example, print(“MyComponentA has been created.") will be replaced with logger.info(None, “MyComponentA has been created.").
Finally, we will force an exception in the my_task method. As we had explained in the “Creating a component” tutorial, this method performs business-related tasks. Thus, we can simulate a problem within it by forcibly raising an exception. This method will look like this:
public myTask(correlationId: string): void {
// create an artificial problem
try{
throw Error('Logging demo. Error created');
}
catch (ex) {
logger.error(correlationId, ex, "Error created.")
}
}
public void MyTask(string correlationId)
{
var logger = new ConsoleLogger();
logger.Level = LogLevel.Debug;
// create an artificial problem
try
{
throw new Exception("Logging demo. Error created");
}
catch (Exception e)
{
logger.Error(correlationId, e, "Error created.");
}
}
func MyTask(correlationId string) {
// create an artificial problem
err := errors.New("Logging demo. Error created")
logger.Error(context.Background(), correlationId, err, "Error created.")
}
void myTask(String? correlationId) {
// create an artificial problem
try {
throw Exception('Logging demo. Error created');
} catch (ex) {
logger.error(correlationId, ex as Exception, 'Error created.');
}
}
def my_task(self, correlation_id):
# create an artificial problem
try:
raise Exception('Logging demo', 'Error created')
except Exception as inst:
logger.error(correlation_id, inst, "Error created.")
And, our final code will look like this:
a) Our components
import { ConfigParams, Descriptor, ICleanable, IOpenable, IUnreferenceable } from 'pip-services3-commons-nodex';
import { IConfigurable } from 'pip-services3-commons-nodex';
import { IReferences } from 'pip-services3-commons-nodex';
import { IReferenceable } from 'pip-services3-commons-nodex';
import { CompositeLogger, ConsoleLogger, Factory } from 'pip-services3-components-nodex';
export class MyComponentB implements IReferenceable, IUnreferenceable, IConfigurable, IOpenable, ICleanable {
private _param1: string = 'ABC2';
private _param2: number = 456;
private _opened:boolean = false;
private _status: string;
private _logger = new ConsoleLogger();
/**
* Creates a new instance of the component.
*/
public constructor(){
this._status = 'Created';
this._logger.setLevel(5);
this._logger.info(null, "MyComponentB has been configured.");
}
public configure(config: ConfigParams): void {
this._param1 = config.getAsStringWithDefault('param1', this._param1);
this._param2 = config.getAsIntegerWithDefault('param2', this._param2);
this._logger.info(null, "MyComponentB has been configured.")
}
public setReferences(refs: IReferences): void {
// pass
}
public isOpen(): boolean {
// pass
}
public open(correlationId: string): Promise<void> {
// pass
}
public close(correlationId: string): Promise<void> {
// pass
}
public myTask(correlationId: string): void {
// create an artificial problem
try {
throw Error('Logging demo. Error created');
}
catch (ex) {
this._logger.error(correlationId, ex, "Error created.")
}
}
/**
* Unsets (clears) previously set references to dependent components.
*/
public unsetReferences(): void {
// pass
}
/**
* Clears component state.
* @param correlationId (optional) transaction id to trace execution through call chain.
*/
public clear(correlationId: string): Promise<void> {
// pass
return;
}
}
export class MyComponentA implements IReferenceable, IUnreferenceable, IConfigurable, IOpenable, ICleanable {
private _param1: string = 'ABC';
private _param2: number = 123;
private _opened: boolean = false;
private _status: string;
private _another_component: MyComponentB;
public dummy_variable = "resource variable";
private _logger = new ConsoleLogger();
/**
* Creates a new instance of the component.
*/
public constructor() {
this._status = 'Created';
this._logger.setLevel(5);
this._logger.info(null, "MyComponentA has been configured.");
}
public configure(config: ConfigParams): void {
this._param1 = config.getAsStringWithDefault('param1', this._param1);
this._param2 = config.getAsIntegerWithDefault('param2', this._param2);
this._status = "Configured";
this._logger.info(null, "MyComponentA has been configured.")
}
public setReferences(refs: IReferences): void {
this._another_component = refs.getOneRequired(
new Descriptor("myservice", "mycomponent-b", "*", "*", "1.0")
)
this._status = "Configured"
this._logger.info(null, "MyComponentA's references have been defined.")
}
public isOpen(): boolean {
return this._opened;
}
public open(correlationId: string): Promise<void> {
this._opened = true;
this._status = "Open";
this._logger.info(correlationId, "MyComponentA has been opened.")
// artificial problem
this.myTask(correlationId);
}
public close(correlationId: string): Promise<void> {
this._opened = false;
this._status = "Closed";
this._logger.info(correlationId, "MyComponentA has been closed.");
}
public myTask(correlationId: string): void {
// create an artificial problem
try {
throw Error('Logging demo. Error created');
}
catch (ex) {
this._logger.error(correlationId, ex, "Error created.")
}
}
/**
* Unsets (clears) previously set references to dependent components.
*/
public unsetReferences(): void {
this._another_component = null;
this._status = "Un-referenced";
this._logger.info(null, "References cleared");
}
/**
* Clears component state.
* @param correlationId (optional) transaction id to trace execution through call chain.
*/
public clear(correlationId: string): Promise<void> {
this.dummy_variable = null;
this._status = null;
this._logger.info(null, "Resources cleared");
}
}
using PipServices3.Commons.Config;
using PipServices3.Commons.Refer;
using PipServices3.Commons.Run;
using PipServices3.Components.Log;
using System;
using System.Threading.Tasks;
namespace ExampleApp
{
class MyComponentB : IReferenceable, IUnreferenceable, IConfigurable, IOpenable, ICleanable
{
private string _param1 = "ABC2";
private int _param2 = 456;
private bool _opened = false;
private string _status;
private ConsoleLogger _logger = new ConsoleLogger();
/// <summary>
/// Creates a new instance of the component.
/// </summary>
public MyComponentB()
{
this._status = "Created";
this._logger.Level = LogLevel.Debug;
this._logger.Info(null, "MyComponentB has been configured.");
}
public void Configure(ConfigParams config)
{
this._param1 = config.GetAsStringWithDefault("param1", this._param1);
this._param2 = config.GetAsIntegerWithDefault("param2", this._param2);
this._logger.Info(null, "MyComponentB has been configured.");
}
public void SetReferences(IReferences references)
{
}
public bool IsOpen()
{
return _opened;
}
public async Task OpenAsync(string correlationId)
{
await Task.FromResult(0);
}
public async Task CloseAsync(string correlationId)
{
await Task.FromResult(0);
}
public void MyTask(string correlationId)
{
var logger = new ConsoleLogger();
logger.Level = LogLevel.Debug;
// create an artificial problem
try
{
throw new Exception("Logging demo. Error created");
}
catch (Exception e)
{
logger.Error(correlationId, e, "Error created.");
}
}
/// <summary>
/// Unsets (clears) previously set references to dependent components.
/// </summary>
public void UnsetReferences()
{
}
/// <summary>
/// Clears component state.
/// </summary>
/// <param name="correlationId">(optional) transaction id to trace execution through call chain.</param>
/// <returns></returns>
public async Task ClearAsync(string correlationId)
{
await Task.FromResult(0);
}
}
class MyComponentA : IReferenceable, IUnreferenceable, IConfigurable, IOpenable, ICleanable
{
private string _param1 = "ABC";
private int _param2 = 123;
private bool _opened = false;
private string _status;
private MyComponentB _another_component;
private ConsoleLogger _logger = new ConsoleLogger();
public string dummy_variable = "resource variable";
/// <summary>
/// Creates a new instance of the component.
/// </summary>
public MyComponentA()
{
this._status = "Created";
this._logger.Level = LogLevel.Debug;
this._logger.Info(null, "MyComponentA has been configured.");
}
public void Configure(ConfigParams config)
{
this._param1 = config.GetAsStringWithDefault("param1", this._param1);
this._param2 = config.GetAsIntegerWithDefault("param2", this._param2);
this._status = "Configured";
this._logger.Info(null, "MyComponentA has been configured.");
}
public void SetReferences(IReferences references)
{
this._another_component = references.GetOneRequired(
new Descriptor("myservice", "mycomponent-b", "*", "*", "1.0")
) as MyComponentB;
this._status = "Configured";
this._logger.Info(null, "MyComponentA's references have been defined.");
}
public bool IsOpen()
{
return this._opened;
}
public async Task OpenAsync(string correlationId)
{
this._opened = true;
this._status = "Open";
this._logger.Info(correlationId, "MyComponentA has been opened.");
// artificial problem
this.MyTask(correlationId);
await Task.FromResult(0);
}
public async Task CloseAsync(string correlationId)
{
this._opened = false;
this._status = "Closed";
this._logger.Info(correlationId, "MyComponentA has been closed.");
await Task.FromResult(0);
}
public void MyTask(string correlationId)
{
var logger = new ConsoleLogger();
logger.Level = LogLevel.Debug;
// create an artificial problem
try
{
throw new Exception("Logging demo. Error created");
}
catch (Exception e)
{
logger.Error(correlationId, e, "Error created.");
}
}
/// <summary>
/// Unsets (clears) previously set references to dependent components.
/// </summary>
public void UnsetReferences()
{
this._another_component = null;
this._status = "Un-referenced";
this._logger.Info(null, "References cleared");
}
/// <summary>
/// Clears component state.
/// </summary>
/// <param name="correlationId">(optional) transaction id to trace execution through call chain.</param>
/// <returns></returns>
public async Task ClearAsync(string correlationId)
{
this.dummy_variable = null;
this._status = null;
this._logger.Info(null, "Resources cleared");
await Task.FromResult(0);
}
}
}
import (
"context"
"errors"
cconfig "github.com/pip-services3-gox/pip-services3-commons-gox/config"
crefer "github.com/pip-services3-gox/pip-services3-commons-gox/refer"
crun "github.com/pip-services3-gox/pip-services3-commons-gox/run"
clog "github.com/pip-services3-gox/pip-services3-components-gox/log"
)
type MyComponentB struct {
crefer.IReferences
crefer.IUnreferenceable
cconfig.IConfigurable
crun.IOpenable
crun.ICleanable
_status string
_param1 string
_param2 int
_opened bool
_logger clog.ILogger
dummy_variable interface{}
}
// Creates a new instance of the component.
func NewMyComponentB() *MyComponentB {
component := &MyComponentB{
_status: "Created",
_param1: "ABC2",
_param2: 456,
_opened: false,
_logger: clog.NewConsoleLogger(),
dummy_variable: "resource variable",
}
component._logger.SetLevel(5)
component._logger.Info(context.Background(), "123", "MyComponentB has been created.")
return component
}
func (c *MyComponentB) Configure(ctx context.Context, config *cconfig.ConfigParams) {
c._param1 = config.GetAsStringWithDefault("param1", c._param1)
c._param2 = config.GetAsIntegerWithDefault("param2", c._param2)
c._logger.Info(ctx, "123", "MyComponentB has been configured.")
}
func (c *MyComponentB) SetReferences(ctx context.Context, references *crefer.References) {
// pass
}
func (c *MyComponentB) isOpen() bool {
// pass
return true
}
func (c *MyComponentB) Open(ctx context.Context, correlationId string) {
// pass
}
func (c *MyComponentB) Close(ctx context.Context, correlationId string) {
// pass
}
func (c *MyComponentB) MyTask(ctx context.Context, correlationId string) {
// pass
}
// Unsets (clears) previously set references to dependent components.
func (c *MyComponentB) UnsetReferences(ctx context.Context) {
// pass
}
// Clears component state.
// - correlationId: (optional) transaction id to trace execution through call chain.
func (c *MyComponentB) Clear(ctx context.Context, correlationId string) {
// pass
}
type MyComponentA struct {
crefer.IReferences
crefer.IUnreferenceable
cconfig.IConfigurable
crun.IOpenable
crun.ICleanable
_logger clog.ILogger
_status string
_param1 string
_param2 int
_opened bool
dummy_variable interface{}
_another_component interface{}
}
// Creates a new instance of the component.
func NewMyComponentA() *MyComponentA {
component := &MyComponentA{
_status: "Created",
_param1: "ABC2",
_param2: 456,
_opened: false,
_logger: clog.NewConsoleLogger(),
dummy_variable: "dummy_variable setted",
}
component._logger.SetLevel(5)
component._logger.Info(context.Background(), "123", "MyComponentA has been created.")
return component
}
func (c *MyComponentA) Configure(ctx context.Context, config *cconfig.ConfigParams) {
c._param1 = config.GetAsStringWithDefault("param1", c._param1)
c._param2 = config.GetAsIntegerWithDefault("param2", c._param2)
c._status = "Configured"
c._logger.Info(ctx, "123", "MyComponentB has been configured.")
}
func (c *MyComponentA) SetReferences(ctx context.Context, references *crefer.References) {
_another_component, err := references.GetOneRequired(crefer.NewDescriptor("myservice", "mycomponent-b", "*", "*", "1.0"))
if err != nil {
panic("Error: Another Component is not in refs")
}
c._another_component = _another_component.(MyComponentB)
c._status = "Configured"
c._logger.Info(ctx, "123", "MyComponentA's references have been defined.")
}
func (c *MyComponentA) isOpen() bool {
return c._opened
}
func (c *MyComponentA) Open(ctx context.Context, correlationId string) {
c._opened = true
c._status = "Open"
c._logger.Info(ctx, correlationId, "MyComponentA has been opened.")
// artificial problem
c.MyTask(ctx, correlationId)
}
func (c *MyComponentA) Close(ctx context.Context, correlationId string) {
c._opened = false
c._status = "Closed"
c._logger.Info(ctx, correlationId, "MyComponentA has been closed.")
}
func (c *MyComponentA) MyTask(ctx context.Context, correlationId string) {
// create an artificial problem
c._logger.Error(ctx, correlationId, errors.New("Logging demo. Error created"), "Error created.")
}
// Unsets (clears) previously set references to dependent components.
func (c *MyComponentA) UnsetReferences(ctx context.Context) {
c._another_component = nil
c._status = "Un-referenced"
c._logger.Info(ctx, "123", "References cleared")
}
// Clears component state.
// - correlationId: (optional) transaction id to trace execution through call chain.
func (c *MyComponentA) Clear(ctx context.Context, correlationId string) {
c.dummy_variable = nil
c._status = ""
c._logger.Info(ctx, correlationId, "Resources cleared")
}
import 'package:pip_services3_commons/pip_services3_commons.dart';
import 'package:pip_services3_components/pip_services3_components.dart';
class MyComponentB
implements
IReferenceable,
IUnreferenceable,
IConfigurable,
IOpenable,
ICleanable {
String _param1 = 'ABC2';
int _param2 = 456;
bool _opened = false;
String? _status;
var _logger = ConsoleLogger();
/// Creates a new instance of the component.
MyComponentB() {
_status = 'Created';
_logger.setLevel(LogLevel.Debug);
_logger.info(null, 'MyComponentB has been configured.');
}
@override
void configure(ConfigParams config) {
_param1 = config.getAsStringWithDefault('param1', _param1);
_param2 = config.getAsIntegerWithDefault('param2', _param2);
_logger.info(null, 'MyComponentB has been configured.');
}
void myTask(String? correlationId) {
// create an artificial problem
try {
throw Exception('Logging demo. Error created');
} catch (ex) {
_logger.error(correlationId, ex as Exception, 'Error created.');
}
}
@override
void setReferences(IReferences references) {
// pass
}
@override
bool isOpen() {
// pass
return true;
}
@override
Future open(String? correlationId) async {
// pass
}
@override
Future close(String? correlationId) async {
// pass
}
/// Clears component state.
@override
Future clear(String? correlationId) async {
// pass
}
/// Unsets (clears) previously set references to dependent components.
@override
void unsetReferences() {
// pass
}
}
class MyComponentA
implements
IReferenceable,
IUnreferenceable,
IConfigurable,
IOpenable,
ICleanable {
String _param1 = 'ABC';
int _param2 = 123;
bool _opened = false;
String? _status;
MyComponentB? _anotherComponent;
String? dummyVariable = 'resource variable';
var _logger = ConsoleLogger();
/// Creates a new instance of the component.
MyComponentA() : _status = 'Created' {
_logger.setLevel(LogLevel.Debug);
_logger.info(null, 'MyComponentA has been configured.');
}
@override
void configure(ConfigParams config) {
_param1 = config.getAsStringWithDefault('param1', _param1);
_param2 = config.getAsIntegerWithDefault('param2', _param2);
_status = 'Configured';
_logger.info(null, 'MyComponentB has been configured.');
}
void myTask(String? correlationId) {
// create an artificial problem
try {
throw Exception('Logging demo. Error created');
} catch (ex) {
_logger.error(correlationId, ex as Exception, 'Error created.');
}
}
@override
void setReferences(IReferences references) {
_anotherComponent = references.getOneRequired(
Descriptor('myservice', 'mycomponent-b', '*', '*', '1.0'));
_status = 'Configured';
_logger.info(null, "MyComponentA's references have been defined.");
}
@override
bool isOpen() {
return _opened;
}
@override
Future open(String? correlationId) async {
_opened = true;
_status = 'Open';
_logger.info(correlationId, 'MyComponentA has been opened.');
// artificial problem
myTask(correlationId);
}
@override
Future close(String? correlationId) async {
_opened = false;
_status = 'Closed';
_logger.info(correlationId, 'MyComponentA has been closed.');
}
/// Clears component state.
@override
Future clear(String? correlationId) async {
dummyVariable = null;
_status = null;
_logger.info(null, 'Resources cleared');
}
/// Unsets (clears) previously set references to dependent components.
@override
void unsetReferences() {
_anotherComponent = null;
_status = 'Un-referenced';
_logger.info(null, 'References cleared');
}
}
from pip_services3_commons.config import IConfigurable, ConfigParams, IExecutable
from pip_services3_commons.refer import IReferenceable, IReferences, Descriptor, IUnreferenceable
from pip_services3_commons.run import IOpenable, ICleanable
from pip_services3_components.log import ConsoleLogger, LogLevel
class MyComponentB(IReferenceable, IUnreferenceable, IConfigurable, IOpenable, ICleanable):
_param1 = 'ABC2'
_param2 = 456
_opened = False
dummy_variable = "resource variable"
def __init__(self):
"""
Creates a new instance of the component.
"""
self._status = "Created"
logger.info(None, "MyComponentB has been created.")
def configure(self, config):
self._param1 = config.get_as_string_with_default("param1", self._param1)
self._param2 = config.get_as_integer_with_default("param2", self._param2)
logger.info(None, "MyComponentB has been configured.")
def set_references(self, references):
pass
def is_open(self):
pass
def open(self, correlation_id):
pass
def close(self, correlation_id):
pass
def my_task(self, correlation_id):
pass
def unset_references(self):
"""
Unsets (clears) previously set references to dependent components.
"""
pass
def clear(self, correlation_id):
"""
Clears component state.
:param correlation_id: (optional) transaction id to trace execution through call chain.
"""
pass
class MyComponentA(IReferenceable, IUnreferenceable, IConfigurable, IOpenable, ICleanable, IExecutable):
_param1 = 'ABC'
_param2 = 123
_another_component: MyComponentB
_open = False
_status = None
def __init__(self):
"""
Creates a new instance of the component.
"""
self._status = "Created"
logger.info(None, "MyComponentA has been created.")
def configure(self, config):
self._param1 = config.get_as_string_with_default("param1", 'ABC')
self._param2 = config.get_as_integer_with_default("param2", 123)
self._status = "Configured"
logger.info(None,"MyComponentA has been configured.")
def set_references(self, references):
self._another_component = references.get_one_required(
Descriptor("myservice", "mycomponent-b", "*", "*", "1.0")
)
self._status = "Configured"
logger.info(None,"MyComponentA's references have been defined.")
def is_open(self):
return self._open
def open(self, correlation_id):
self._open = True
self._status = "Open"
logger.info(None,"MyComponentA has been opened.")
# artificial problem
self.my_task(correlation_id)
def close(self, correlation_id):
self._opened = False
self._status = "Closed"
logger.info(correlation_id,"MyComponentA has been closed.")
def my_task(self, correlation_id):
# create an artificial problem
try:
raise Exception('Logging demo', 'Error created')
except Exception as inst:
logger.error(correlation_id, inst, "Error created.")
def unset_references(self):
"""
Unsets (clears) previously set references to dependent components.
"""
self._another_component = None
self._status = "Un-referenced"
logger.info(None, "References cleared")
def clear(self, correlation_id):
"""
Clears component state.
:param correlation_id: (optional) transaction id to trace execution through call chain.
"""
self.dummy_variable = None
self._status = None
logger.info(correlation_id, "Resources cleared")
b) Our factory
// Creating a factory
import { Factory } from 'pip-services3-components-nodex';
let MyFactory1 = new Factory();
MyFactory1.registerAsType(new Descriptor("myservice", "mycomponentA", "default", "*", "1.0"), MyComponentA)
MyFactory1.registerAsType(new Descriptor("myservice", "mycomponent-b", "default", "*", "1.0"), MyComponentB)
using PipServices3.Commons.Refer;
using PipServices3.Components.Build;
var MyFactory1 = new Factory();
MyFactory1.RegisterAsType(new Descriptor("myservice", "mycomponentA", "default", "*", "1.0"), typeof(MyComponentA));
MyFactory1.RegisterAsType(new Descriptor("myservice", "mycomponent-b", "default", "*", "1.0"), typeof(MyComponentB));
// Creating a factory
import (
cbuild "github.com/pip-services3-gox/pip-services3-components-gox/build"
)
MyFactory1 := cbuild.NewFactory()
MyFactory1.RegisterType(crefer.NewDescriptor("myservice", "mycomponentA", "default", "*", "1.0"), NewMyComponentA)
MyFactory1.RegisterType(crefer.NewDescriptor("myservice", "mycomponent-b", "default", "*", "1.0"), NewMyComponentB)
// Creating a factory
var MyFactory1 = Factory();
MyFactory1.registerAsType(
Descriptor('myservice', 'mycomponentA', 'default', '*', '1.0'),
MyComponentA);
MyFactory1.registerAsType(
Descriptor('myservice', 'mycomponent-b', 'default', '*', '1.0'),
MyComponentB);
# Creating a factory
from pip_services3_components.build import Factory
MyFactory1 = Factory()
MyFactory1.register_as_type(Descriptor("myservice", "mycomponentA", "default", "*", "1.0"), MyComponentA)
MyFactory1.register_as_type(Descriptor("myservice", "mycomponent-b", "default", "*", "1.0"), MyComponentB)
c) Our service
// Creating a process container
class MyProcess extends ProcessContainer{
public constructor() {
super('myservice', 'My service running as a process');
this._configPath = './config.yaml'
this._factories.add(MyFactory1)
}
}
using PipServices3.Components.Build;
using PipServices3.Components.Refer;
using PipServices3.Container;
// Creating a process container
class MyProcess : ProcessContainer
{
public MyProcess() : base("myservice", "My service running as a process")
{
this._configPath = "../../../../../config/config.yml";
var MyFactory1 = new Factory();
MyFactory1.RegisterAsType(new Descriptor("myservice", "mycomponentA", "default", "*", "1.0"), typeof(MyComponentA));
MyFactory1.RegisterAsType(new Descriptor("myservice", "mycomponent-b", "default", "*", "1.0"), typeof(MyComponentB));
this._factories.Add(MyFactory1);
}
}
// Creating a process container
type MyProcess struct {
*cproc.ProcessContainer
}
func NewMyProcess() *MyProcess {
c := MyProcess{}
c.ProcessContainer = cproc.NewProcessContainer("myservice", "My service running as a process")
c.SetConfigPath("./config/config.yml")
MyFactory1 := cbuild.NewFactory()
MyFactory1.RegisterType(crefer.NewDescriptor("myservice", "mycomponentA", "default", "*", "1.0"), NewMyComponentA)
MyFactory1.RegisterType(crefer.NewDescriptor("myservice", "mycomponent-b", "default", "*", "1.0"), NewMyComponentB)
c.AddFactory(MyFactory1)
return &c
}
// Creating a process container
class MyProcess extends ProcessContainer {
MyProcess() : super('myservice', 'My service running as a process') {
configPath = './config.yaml';
factories.add(MyFactory1);
}
}
# Creating a process container
from pip_services3_container import ProcessContainer
class MyProcess(ProcessContainer):
def __init__(self):
super(MyProcess, self).__init__('myservice', 'My service running as a process')
self._config_path = 'E:\\config2.yaml'
self._factories.add(MyFactory1)
d) The dynamic configuration file for the components:
config.yaml
---
- descriptor: "myservice:mycomponentA:*:default:1.0"
param1: XYZ
param2: 987
- descriptor: myservice:mycomponent-b:*:*:1.0
param1: XYZ
param2: 987
e) Running our service
let MyProcess = require('./obj/example').MyProcess;
try {
let proc = new MyProcess();
proc.run(process.argv);
} catch (ex) {
console.error(ex);
}
using System;
namespace ExampleApp
{
class Program
{
static void Main(string[] args)
{
try
{
var task = (new MyProcess()).RunAsync(args);
task.Wait();
}
catch (Exception ex)
{
Console.Error.WriteLine(ex);
}
}
}
}
package main
func main() {
proc := NewMyProcess()
proc.Run(context.Background(), os.Environ())
}
void main(List<String> arguments) async {
try {
var proc = MyProcess();
proc.run(arguments);
} catch (ex) {
print(ex);
}
}
# -*- coding: utf-8 -*-
if __name__ == '__main__':
runner = MyProcess()
print("Run")
try:
runner.run()
except Exception as ex:
print(ex)
After running this code, we will get the following result:
As we can see from the above figure, the program has logged all messages with level info and from our artificial error.
This concludes our first task.
Adding a composite logger to our component
Now, we will extend our logging capacity by adding a composite logger. This logger will allow us to aggregate all loggers from our component’s references into a centralized log. Our code will remain the same, except that now we need to create a composite logger for MyComponentA. For this, we will create an instance of this logger and set the logging level to 5.
Then, we will use the configure and set_references methods to let our composite logger know where to ask for log messages. Our factory and process container code sections will remain the same, but we will have to add a reference to our console logger in our configuration file. The syntax will be:
# Console logger
- descriptor: "pip-services:logger:console:default:1.0"
level: {{LOG_LEVEL}}{{^LOG_LEVEL}}info{{/LOG_LEVEL}}
Finally, we will add a console logger to MyComponentB. After these changes, our component section will look like this:
import { ConfigParams, Descriptor, ICleanable, IOpenable, IUnreferenceable } from 'pip-services3-commons-nodex';
import { IConfigurable } from 'pip-services3-commons-nodex';
import { IReferences } from 'pip-services3-commons-nodex';
import { IReferenceable } from 'pip-services3-commons-nodex';
import { CompositeLogger, ConsoleLogger, Factory } from 'pip-services3-components-nodex';
import { ProcessContainer } from 'pip-services3-container-nodex';
export class MyComponentB implements IReferenceable, IUnreferenceable, IConfigurable, IOpenable, ICleanable {
private _param1: string = 'ABC2';
private _param2: number = 456;
private _opened:boolean = false;
private _status: string;
private _logger = new ConsoleLogger();
/**
* Creates a new instance of the component.
*/
public constructor(){
this._status = 'Created';
this._logger.setLevel(5);
this._logger.info(null, "MyComponentB has been configured.");
}
public configure(config: ConfigParams): void {
this._param1 = config.getAsStringWithDefault('param1', this._param1);
this._param2 = config.getAsIntegerWithDefault('param2', this._param2);
this._logger.info(null, "MyComponentB has been configured.")
}
public setReferences(refs: IReferences): void {
// pass
}
public isOpen(): boolean {
// pass
}
public open(correlationId: string): Promise<void> {
// pass
}
public close(correlationId: string): Promise<void> {
// pass
}
public myTask(correlationId: string): void {
// create an artificial problem
try {
throw Error('Logging demo. Error created');
}
catch (ex) {
this._logger.error(correlationId, ex, "Error created.")
}
}
/**
* Unsets (clears) previously set references to dependent components.
*/
public unsetReferences(): void {
// pass
}
/**
* Clears component state.
* @param correlationId (optional) transaction id to trace execution through call chain.
*/
public clear(correlationId: string): Promise<void> {
// pass
}
}
export class MyComponentA implements IReferenceable, IUnreferenceable, IConfigurable, IOpenable, ICleanable {
private _param1: string = 'ABC';
private _param2: number = 123;
private _opened: boolean = false;
private _status: string;
private _another_component: MyComponentB;
public dummy_variable = "resource variable";
private _logger = new CompositeLogger();
/**
* Creates a new instance of the component.
*/
public constructor() {
this._status = 'Created';
this._logger.setLevel(5);
this._logger.info(null, "MyComponentA has been configured.");
}
public configure(config: ConfigParams): void {
this._param1 = config.getAsStringWithDefault('param1', this._param1);
this._param2 = config.getAsIntegerWithDefault('param2', this._param2);
this._status = "Configured";
this._logger.info(null, "MyComponentA has been configured.")
}
public setReferences(refs: IReferences): void {
this._another_component = refs.getOneRequired(
new Descriptor("myservice", "mycomponent-b", "*", "*", "1.0")
)
this._status = "Configured"
this._logger.setReferences(refs);
this._logger.info(null, "MyComponentA's references have been defined.")
}
public isOpen(): boolean {
return this._opened;
}
public open(correlationId: string): Promise<void> {
this._opened = true;
this._status = "Open";
this._logger.info(correlationId, "MyComponentA has been opened.")
// artificial problem
this.myTask(correlationId);
}
public close(correlationId: string): Promise<void> {
this._opened = false;
this._status = "Closed";
this._logger.info(correlationId, "MyComponentA has been closed.");
}
public myTask(correlationId: string): void {
// create an artificial problem
try {
throw Error('Logging demo. Error created');
}
catch (ex) {
this._logger.error(correlationId, ex, "Error created.")
}
}
/**
* Unsets (clears) previously set references to dependent components.
*/
public unsetReferences(): void {
this._another_component = null;
this._status = "Un-referenced";
this._logger.info(null, "References cleared");
}
/**
* Clears component state.
* @param correlationId (optional) transaction id to trace execution through call chain.
*/
public clear(correlationId: string): Promise<void> {
this.dummy_variable = null;
this._status = null;
this._logger.info(null, "Resources cleared");
}
}
using PipServices3.Commons.Config;
using PipServices3.Commons.Refer;
using PipServices3.Commons.Run;
using PipServices3.Components.Log;
using PipServices3.Container;
using System;
using System.Threading.Tasks;
namespace ExampleApp
{
class MyComponentB : IReferenceable, IUnreferenceable, IConfigurable, IOpenable, ICleanable
{
private string _param1 = "ABC2";
private int _param2 = 456;
private bool _opened = false;
private string _status;
private ConsoleLogger _logger = new ConsoleLogger();
/// <summary>
/// Creates a new instance of the component.
/// </summary>
public MyComponentB()
{
this._status = "Created";
this._logger.Level = LogLevel.Debug;
this._logger.Info(null, "MyComponentB has been configured.");
}
public void Configure(ConfigParams config)
{
this._param1 = config.GetAsStringWithDefault("param1", this._param1);
this._param2 = config.GetAsIntegerWithDefault("param2", this._param2);
this._logger.Info(null, "MyComponentB has been configured.");
}
public void SetReferences(IReferences references)
{
}
public bool IsOpen()
{
return _opened;
}
public async Task OpenAsync(string correlationId)
{
await Task.FromResult(0);
}
public async Task CloseAsync(string correlationId)
{
await Task.FromResult(0);
}
public void MyTask(string correlationId)
{
var logger = new ConsoleLogger();
logger.Level = LogLevel.Debug;
// create an artificial problem
try
{
throw new Exception("Logging demo. Error created");
}
catch (Exception e)
{
logger.Error(correlationId, e, "Error created.");
}
}
/// <summary>
/// Unsets (clears) previously set references to dependent components.
/// </summary>
public void UnsetReferences()
{
}
/// <summary>
/// Clears component state.
/// </summary>
/// <param name="correlationId">(optional) transaction id to trace execution through call chain.</param>
/// <returns></returns>
public async Task ClearAsync(string correlationId)
{
await Task.FromResult(0);
}
}
class MyComponentA : IReferenceable, IUnreferenceable, IConfigurable, IOpenable, ICleanable
{
private string _param1 = "ABC";
private int _param2 = 123;
private bool _opened = false;
private string _status;
private MyComponentB _another_component;
private CompositeLogger _logger = new CompositeLogger();
public string dummy_variable = "resource variable";
/// <summary>
/// Creates a new instance of the component.
/// </summary>
public MyComponentA()
{
this._status = "Created";
this._logger.Level = LogLevel.Debug;
this._logger.Info(null, "MyComponentA has been configured.");
}
public void Configure(ConfigParams config)
{
this._param1 = config.GetAsStringWithDefault("param1", this._param1);
this._param2 = config.GetAsIntegerWithDefault("param2", this._param2);
this._status = "Configured";
this._logger.Info(null, "MyComponentA has been configured.");
}
public void SetReferences(IReferences references)
{
this._another_component = references.GetOneRequired(
new Descriptor("myservice", "mycomponent-b", "*", "*", "1.0")
) as MyComponentB;
this._logger.SetReferences(references);
this._status = "Configured";
this._logger.Info(null, "MyComponentA's references have been defined.");
}
public bool IsOpen()
{
return this._opened;
}
public async Task OpenAsync(string correlationId)
{
this._opened = true;
this._status = "Open";
this._logger.Info(correlationId, "MyComponentA has been opened.");
// artificial problem
this.MyTask(correlationId);
await Task.FromResult(0);
}
public async Task CloseAsync(string correlationId)
{
this._opened = false;
this._status = "Closed";
this._logger.Info(correlationId, "MyComponentA has been closed.");
await Task.FromResult(0);
}
public void MyTask(string correlationId)
{
var logger = new ConsoleLogger();
logger.Level = LogLevel.Debug;
// create an artificial problem
try
{
throw new Exception("Logging demo. Error created");
}
catch (Exception e)
{
logger.Error(correlationId, e, "Error created.");
}
}
/// <summary>
/// Unsets (clears) previously set references to dependent components.
/// </summary>
public void UnsetReferences()
{
this._another_component = null;
this._status = "Un-referenced";
this._logger.Info(null, "References cleared");
}
/// <summary>
/// Clears component state.
/// </summary>
/// <param name="correlationId">(optional) transaction id to trace execution through call chain.</param>
/// <returns></returns>
public async Task ClearAsync(string correlationId)
{
this.dummy_variable = null;
this._status = null;
this._logger.Info(null, "Resources cleared");
await Task.FromResult(0);
}
}
}
import (
"context"
"errors"
"os"
cconfig "github.com/pip-services3-gox/pip-services3-commons-gox/config"
crefer "github.com/pip-services3-gox/pip-services3-commons-gox/refer"
crun "github.com/pip-services3-gox/pip-services3-commons-gox/run"
cbuild "github.com/pip-services3-gox/pip-services3-components-gox/build"
clog "github.com/pip-services3-gox/pip-services3-components-gox/log"
cproc "github.com/pip-services3-gox/pip-services3-container-gox/container"
)
type MyComponentB struct {
crefer.IReferences
crefer.IUnreferenceable
cconfig.IConfigurable
crun.IOpenable
crun.ICleanable
_logger *clog.ConsoleLogger
_status string
_param1 string
_param2 int
_opened bool
}
// Creates a new instance of the component.
func NewMyComponentB() *MyComponentB {
component := &MyComponentB{
_status: "Created",
_param1: "ABC2",
_param2: 456,
_opened: false,
_logger: clog.NewConsoleLogger(),
}
component._logger.SetLevel(5)
component._logger.Info(context.Background(), "123", "MyComponentB has been created.")
return component
}
func (c *MyComponentB) Configure(ctx context.Context, config *cconfig.ConfigParams) {
c._param1 = config.GetAsStringWithDefault("param1", c._param1)
c._param2 = config.GetAsIntegerWithDefault("param2", c._param2)
c._logger.Info(ctx, "123", "MyComponentB has been configured.")
}
func (c *MyComponentB) SetReferences(ctx context.Context, references *crefer.References) {
// pass
}
func (c *MyComponentB) isOpen() bool {
// pass
return true
}
func (c *MyComponentB) Open(ctx context.Context, correlationId string) {
// pass
}
func (c *MyComponentB) Close(ctx context.Context, correlationId string) {
// pass
}
func (c *MyComponentB) MyTask(ctx context.Context, correlationId string) {
// pass
}
// Unsets (clears) previously set references to dependent components.
func (c *MyComponentB) UnsetReferences(ctx context.Context) {
// pass
}
// Clears component state.
// - correlationId: (optional) transaction id to trace execution through call chain.
func (c *MyComponentB) Clear(ctx context.Context, correlationId string) {
// pass
}
type MyComponentA struct {
crefer.IReferences
crefer.IUnreferenceable
cconfig.IConfigurable
crun.IOpenable
crun.ICleanable
_logger *clog.CompositeLogger
_status string
_param1 string
_param2 int
_opened bool
dummy_variable interface{}
_another_component interface{}
}
// Creates a new instance of the component.
func NewMyComponentA() *MyComponentA {
component := &MyComponentA{
_status: "Created",
_param1: "ABC2",
_param2: 456,
_opened: false,
_logger: clog.NewCompositeLogger(),
dummy_variable: "dummy_variable setted",
}
component._logger.SetLevel(5)
component._logger.Info(context.Background(), "123", "MyComponentA has been created.")
return component
}
func (c *MyComponentA) Configure(ctx context.Context, config *cconfig.ConfigParams) {
c._param1 = config.GetAsStringWithDefault("param1", c._param1)
c._param2 = config.GetAsIntegerWithDefault("param2", c._param2)
c._status = "Configured"
c._logger.Info(ctx, "123", "MyComponentB has been configured.")
}
func (c *MyComponentA) SetReferences(ctx context.Context, references *crefer.References) {
_another_component, err := references.GetOneRequired(crefer.NewDescriptor("myservice", "mycomponent-b", "*", "*", "1.0"))
if err != nil {
panic("Error: Another Component is not in refs")
}
c._another_component = _another_component.(MyComponentB)
c._status = "Configured"
c._logger.Info(ctx, "123", "MyComponentA's references have been defined.")
}
func (c *MyComponentA) isOpen() bool {
return c._opened
}
func (c *MyComponentA) Open(ctx context.Context, correlationId string) {
c._opened = true
c._status = "Open"
c._logger.Info(ctx, "123", "MyComponentA has been opened.")
// artificial problem
c.MyTask(ctx, correlationId)
}
func (c *MyComponentA) Close(ctx context.Context, correlationId string) {
c._opened = false
c._status = "Closed"
c._logger.Info(ctx, correlationId, "MyComponentA has been closed.")
}
func (c *MyComponentA) MyTask(ctx context.Context, correlationId string) {
// create an artificial problem
c._logger.Error(ctx, correlationId, errors.New("Logging demo. Error created"), "Error created.")
}
// Unsets (clears) previously set references to dependent components.
func (c *MyComponentA) UnsetReferences(ctx context.Context) {
c._another_component = nil
c._status = "Un-referenced"
c._logger.Info(ctx, "123", "References cleared")
}
// Clears component state.
// - correlationId: (optional) transaction id to trace execution through call chain.
func (c *MyComponentA) Clear(ctx context.Context, correlationId string) {
c.dummy_variable = nil
c._status = ""
c._logger.Info(ctx, correlationId, "Resources cleared")
}
// Creating a process container
type MyProcess struct {
*cproc.ProcessContainer
}
func NewMyProcess() *MyProcess {
c := MyProcess{}
c.ProcessContainer = cproc.NewProcessContainer("myservice", "My service running as a process")
c.SetConfigPath("./config.yml")
MyFactory1 := cbuild.NewFactory()
MyFactory1.RegisterType(crefer.NewDescriptor("myservice", "mycomponentA", "default", "*", "1.0"), NewMyComponentA)
MyFactory1.RegisterType(crefer.NewDescriptor("myservice", "mycomponent-b", "default", "*", "1.0"), NewMyComponentB)
c.AddFactory(MyFactory1)
return &c
}
func main() {
proc := NewMyProcess()
proc.Run(context.Background(), os.Environ())
}
class MyComponentB
implements
IReferenceable,
IUnreferenceable,
IConfigurable,
IOpenable,
ICleanable {
String _param1 = 'ABC2';
int _param2 = 456;
bool _opened = false;
String? _status;
var _logger = ConsoleLogger();
/// Creates a new instance of the component.
MyComponentB() {
_status = 'Created';
_logger.setLevel(LogLevel.Debug);
_logger.info(null, 'MyComponentB has been configured.');
}
@override
void configure(ConfigParams config) {
_param1 = config.getAsStringWithDefault('param1', _param1);
_param2 = config.getAsIntegerWithDefault('param2', _param2);
_logger.info(null, 'MyComponentB has been configured.');
}
void myTask(String? correlationId) {
// create an artificial problem
try {
throw Exception('Logging demo. Error created');
} catch (ex) {
_logger.error(correlationId, ex as Exception, 'Error created.');
}
}
@override
void setReferences(IReferences references) {
// pass
}
@override
bool isOpen() {
// pass
return true;
}
@override
Future open(String? correlationId) async {
// pass
}
@override
Future close(String? correlationId) async {
// pass
}
/// Clears component state.
@override
Future clear(String? correlationId) async {
// pass
}
/// Unsets (clears) previously set references to dependent components.
@override
void unsetReferences() {
// pass
}
}
class MyComponentA
implements
IReferenceable,
IUnreferenceable,
IConfigurable,
IOpenable,
ICleanable {
String _param1 = 'ABC';
int _param2 = 123;
bool _opened = false;
String? _status;
MyComponentB? _anotherComponent;
String? dummyVariable = 'resource variable';
var _logger = CompositeLogger();
/// Creates a new instance of the component.
MyComponentA() : _status = 'Created' {
_logger.setLevel(LogLevel.Debug);
_logger.info(null, 'MyComponentA has been configured.');
}
@override
void configure(ConfigParams config) {
_param1 = config.getAsStringWithDefault('param1', _param1);
_param2 = config.getAsIntegerWithDefault('param2', _param2);
_status = 'Configured';
_logger.info(null, 'MyComponentB has been configured.');
}
void myTask(String? correlationId) {
// create an artificial problem
try {
throw Exception('Logging demo. Error created');
} catch (ex) {
_logger.error(correlationId, ex as Exception, 'Error created.');
}
}
@override
void setReferences(IReferences references) {
_anotherComponent = references.getOneRequired(
Descriptor('myservice', 'mycomponent-b', '*', '*', '1.0'));
_logger.setReferences(references);
_status = 'Configured';
_logger.info(null, "MyComponentA's references have been defined.");
}
@override
bool isOpen() {
return _opened;
}
@override
Future open(String? correlationId) async {
_opened = true;
_status = 'Open';
_logger.info(correlationId, 'MyComponentA has been opened.');
// artificial problem
myTask(correlationId);
}
@override
Future close(String? correlationId) async {
_opened = false;
_status = 'Closed';
_logger.info(correlationId, 'MyComponentA has been closed.');
}
/// Clears component state.
@override
Future clear(String? correlationId) async {
dummyVariable = null;
_status = null;
_logger.info(null, 'Resources cleared');
}
/// Unsets (clears) previously set references to dependent components.
@override
void unsetReferences() {
_anotherComponent = null;
_status = 'Un-referenced';
_logger.info(null, 'References cleared');
}
}
from pip_services3_commons.config import IConfigurable, ConfigParams
from pip_services3_commons.refer import IReferenceable, IReferences, Descriptor, IUnreferenceable
from pip_services3_commons.run import IOpenable, ICleanable
from pip_services3_components.log import ConsoleLogger, LogLevel, CompositeLogger
class MyComponentB(IReferenceable, IUnreferenceable, IConfigurable, IOpenable, ICleanable):
_param1 = 'ABC2'
_param2 = 456
_opened = False
__logger = ConsoleLogger()
__logger.set_level(5)
dummy_variable = "resource variable"
def __init__(self):
"""
Creates a new instance of the component.
"""
self._status = "Created"
self.__logger.info(None, "MyComponentB has been created.")
def configure(self, config):
self._param1 = config.get_as_string_with_default("param1", self._param1)
self._param2 = config.get_as_integer_with_default("param2", self._param2)
def set_references(self, references):
pass
def is_open(self):
pass
def open(self, correlation_id):
pass
def close(self, correlation_id):
pass
def my_task(self, correlation_id):
pass
def unset_references(self):
"""
Unsets (clears) previously set references to dependent components.
"""
pass
def clear(self, correlation_id):
"""
Clears component state.
:param correlation_id: (optional) transaction id to trace execution through call chain.
"""
pass
class MyComponentA(IReferenceable, IUnreferenceable, IConfigurable, IOpenable, ICleanable):
_param1 = 'ABC'
_param2 = 123
_another_component: MyComponentB
_open = False
_status = None
__logger = CompositeLogger()
__logger.set_level(5)
def __init__(self):
"""
Creates a new instance of the component.
"""
self._status = "Created"
self.__logger.info(None, "MyComponentA has been created.")
def configure(self, config):
self._param1 = config.get_as_string_with_default("param1", 'ABC')
self._param2 = config.get_as_integer_with_default("param2", 123)
self._status = "Configured"
self.__logger.configure(config)
def set_references(self, references):
self._another_component = references.get_one_required(
Descriptor("myservice", "mycomponent-b", "*", "*", "1.0")
)
self._status = "Configured"
self.__logger.set_references(references)
self.__logger.info(None,"MyComponentA's references have been defined.")
def is_open(self):
return self._open
def open(self, correlation_id):
self._open = True
self._status = "Open"
self.__logger.info(None,"MyComponentA has been opened.")
# artificial problem
self.my_task(correlation_id)
def close(self, correlation_id):
self._opened = False
self._status = "Closed"
self.__logger.info(correlation_id,"MyComponentA has been closed.")
def my_task(self, correlation_id):
# create an artificial problem
try:
raise Exception('Logging demo', 'Error created')
except Exception as inst:
self.__logger.error(correlation_id, inst, "Error created.")
def unset_references(self):
"""
Unsets (clears) previously set references to dependent components.
"""
self._another_component = None
self._status = "Un-referenced"
self.__logger.info(None, "References cleared")
def clear(self, correlation_id):
"""
Clears component state.
:param correlation_id: (optional) transaction id to trace execution through call chain.
"""
self.dummy_variable = None
self._status = None
self.__logger.info(correlation_id, "Resources cleared")
Once we run our service with the re-defined components, we will get the following results:
As we can see, we have log messages received from both MyComponentA and MyComponentB.
Adding specific loggers
As we said earlier, PIP.Services has specific loggers for Datadog, Elasticsearch, and Amazon CloudWatch. The process to add any of them to a component is similar to what we saw in our console logger example: we need to declare an instance of the logger, configure it, set the message level, and add the messages we need. Here below are examples of how to define each of them.
a) Datadog
import { DataDogLogger } from 'pip-services-datadog-nodex';
let logger = new DataDogLogger();
logger.configure(ConfigParams.fromTuples(
"credential.access_key", "827349874395872349875493"
));
logger.setLevel(5);
await logger.open("123");
logger.info("123", "My message");
using PipServices3.Commons.Config;
using PipServices3.Components.Log;
using PipServices3.DataDog.Log;
namespace ExampleApp
{
class Program
{
static void Main(string[] args)
{
var logger = new DataDogLogger();
logger.Configure(ConfigParams.FromTuples(
"credential.access_key", "827349874395872349875493"
));
logger.Level = LogLevel.Debug;
logger.OpenAsync("123").Wait();
logger.Info("123", "My message");
}
}
}
package main
import (
cconfig "github.com/pip-services3-gox/pip-services3-commons-gox/config"
logdatadog "github.com/pip-services3-gox/pip-services3-datadog-gox/log"
)
func main() {
logger := logdatadog.NewDataDogLogger()
logger.Configure(context.Background(), cconfig.NewConfigParamsFromTuples(
"credential.access_key", "827349874395872349875493",
))
logger.SetLevel(5)
_ = logger.Open(context.Background(), "123")
logger.Info(context.Background(), "123", "My message")
}
import 'package:pip_services3_datadog/pip_services3_datadog.dart';
var logger = DataDogLogger();
logger.configure(ConfigParams.fromTuples([
'credential.access_key', '827349874395872349875493']));
logger.setLevel(LogLevel.Debug);
await logger.open("123");
logger.info('123', 'My message');
from pip_services3_datadog.log import DataDogLogger
from pip_services3_commons.config import ConfigParams
logger = DataDogLogger()
logger.configure(ConfigParams.from_tuples(
"credential.access_key", "827349874395872349875493"
))
logger.set_level(5)
logger.open("123")
logger.info("123" , "My message")
b) Elasticsearch
import { ElasticSearchLogger } from 'pip-services-elasticsearch-nodex';
let logger = new ElasticSearchLogger();
logger.configure(ConfigParams.fromTuples(
"connection.protocol", "http",
"connection.host", "localhost",
"connection.port", 9200
));
logger.setLevel(5);
await logger.open("123");
logger.info("123", "My message");
using PipServices3.Commons.Config;
using PipServices3.Components.Log;
using PipServices3.ElasticSearch.Log;
namespace ExampleApp
{
class Program
{
static void Main(string[] args)
{
var logger = new ElasticSearchLogger();
logger.Configure(ConfigParams.FromTuples(
"connection.protocol", "http",
"connection.host", "localhost",
"connection.port", 9200
));
logger.Level = LogLevel.Debug;
logger.OpenAsync("123").Wait();
logger.Info("123", "My message");
}
}
}
package main
import (
cconfig "github.com/pip-services3-gox/pip-services3-commons-gox/config"
logelastic "github.com/pip-services3-gox/pip-services3-elasticsearch-gox/log"
)
func main() {
logger := logelastic.NewElasticSearchLogger()
logger.Configure(context.Background(), cconfig.NewConfigParamsFromTuples(
"connection.protocol", "http",
"connection.host", "localhost",
"connection.port", 9200,
))
logger.SetLevel(5)
_ = logger.Open(context.Background(), "123")
logger.Info(context.Background(), "123", "My message")
}
import 'package:pip_services3_elasticsearch/pip_services3_elasticsearch.dart';
var logger = ElasticSearchLogger();
logger.configure(ConfigParams.fromTuples([
'connection.protocol',
'http',
'connection.host',
'localhost',
'connection.port',
9200
]));
logger.setLevel(LogLevel.Debug);
await logger.open("123");
logger.info('123', 'My message');
from pip_services3_elasticsearch.log import ElasticSearchLogger
from pip_services3_commons.config import ConfigParams
logger = ElasticSearchLogger()
logger.configure(ConfigParams.from_tuples(
"connection.protocol", "http",
"connection.host", "localhost",
"connection.port", 9200
))
logger.set_level(5)
logger.open("123")
logger.info("123" , "My message")
c) Amazon CloudWatch
import { CloudWatchLogger } from 'pip-services3-aws-nodex';
let logger = new CloudWatchLogger();
logger.configure(ConfigParams.fromTuples(
"stream", "mystream",
"group", "mygroup",
"connection.region", "us-east-1",
"connection.access_id", "XXXXXXXXXXX",
"connection.access_key", "XXXXXXXXXXX"
));
logger.setLevel(5);
await logger.open("123");
logger.info("123", "My message");
using PipServices3.Aws.Log;
using PipServices3.Commons.Config;
using PipServices3.Components.Log;
namespace ExampleApp
{
class Program
{
static void Main(string[] args)
{
var logger = new CloudWatchLogger();
logger.Configure(ConfigParams.FromTuples(
"stream", "mystream",
"group", "mygroup",
"connection.region", "us-east-1",
"connection.access_id", "XXXXXXXXXXX",
"connection.access_key", "XXXXXXXXXXX"
));
logger.Level = LogLevel.Debug;
logger.OpenAsync("123").Wait();
logger.Info("123", "My message");
}
}
}
package main
import (
cconfig "github.com/pip-services3-gox/pip-services3-commons-gox/config"
logaws "github.com/pip-services3-gox/pip-services3-aws-gox/log"
)
func main() {
logger := logaws.NewCloudWatchLogger()
logger.Configure(context.Background(), cconfig.NewConfigParamsFromTuples(
"stream", "mystream",
"group", "mygroup",
"connection.region", "us-east-1",
"connection.access_id", "XXXXXXXXXXX",
"connection.access_key", "XXXXXXXXXXX",
))
logger.SetLevel(5)
_ = logger.Open(context.Background(), "123")
logger.Info(context.Background(), "123", "My message")
}
import 'package:pip_services3_aws/pip_services3_aws.dart';
var logger = CloudWatchLogger();
logger.configure(ConfigParams.fromTuples([
'stream',
'mystream',
'group',
'mygroup',
'connection.region',
'us-east-1',
'connection.access_id',
'XXXXXXXXXXX',
'connection.access_key',
'XXXXXXXXXXX'
]));
logger.setLevel(LogLevel.Debug);
await logger.open('123');
logger.info('123', 'My message');
from pip_services3_aws.log import CloudWatchLogger
from pip_services3_commons.config import ConfigParams
logger = CloudWatchLogger()
logger.configure(ConfigParams.from_tuples(
"stream", "mystream",
"group", "mygroup",
"connection.region", "us-east-1",
"connection.access_id", "XXXXXXXXXXX",
"connection.access_key", "XXXXXXXXXXX"
))
logger.set_level(5)
logger.open("123")
logger.info("123" , "My message")
Example
In this example, we will combine two features: displaying log information on our console and sending log information to ElasticSearch.
Pre-requisites
In order to be able to create a composite logger for both outputs, we need to import the following components:
import { CompositeLogger, ConsoleLogger, LogLevel } from 'pip-services3-components-nodex';
import { ElasticSearchLogger } from 'pip-services-elasticsearch-nodex';
import { ConfigParams, Descriptor, References } from 'pip-services3-commons-nodex';
using PipServices3.Commons.Config;
using PipServices3.Commons.Refer;
using PipServices3.Components.Log;
using PipServices3.ElasticSearch.Log;
import (
"errors"
"fmt"
cconf "github.com/pip-services3-gox/pip-services3-commons-gox/config"
cref "github.com/pip-services3-gox/pip-services3-commons-gox/refer"
clog "github.com/pip-services3-gox/pip-services3-components-gox/log"
elasticlog "github.com/pip-services3-gox/pip-services3-elasticsearch-gox/log"
)
import (
"errors"
"fmt"
cconf "github.com/pip-services3-gox/pip-services3-commons-gox/config"
cref "github.com/pip-services3-gox/pip-services3-commons-gox/refer"
clog "github.com/pip-services3-gox/pip-services3-components-gox/log"
elasticlog "github.com/pip-services3-gox/pip-services3-elasticsearch-gox/log"
)
from typing import Optional
from pip_services3_commons.config import IConfigurable, ConfigParams
from pip_services3_commons.refer import IReferenceable, IReferences, Descriptor, References
from pip_services3_commons.run import IOpenable
from pip_services3_components.build import Factory
from pip_services3_components.log import ConsoleLogger, CompositeLogger, LogLevel
from pip_services3_container import ProcessContainer
from pip_services3_elasticsearch.build import DefaultElasticSearchFactory
from pip_services3_elasticsearch.log import ElasticSearchLogger
Component creation
The next step is to create our two logging components, namely our console and ElasticSearch. For this, we instantiate the ConsoleLogger and ElasticSearchLogger classes. Our code is:
// ElasticSearchLogger sends a log to ElasticSearch
let elasticSearchLogger = new ElasticSearchLogger();
// Console logger writes messages to console
let consoleLogger = new ConsoleLogger();
// ElasticSearchLogger sends a log to ElasticSearch
var elasticSearchLogger = new ElasticSearchLogger();
// Console logger writes messages to console
var consoleLogger = new ConsoleLogger();
// ElasticSearchLogger sends a log to ElasticSearch
elasticSearchLogger := elasticlog.NewElasticSearchLogger()
// Console logger writes messages to console
consoleLogger := clog.NewConsoleLogger()
// ElasticSearchLogger sends a log to ElasticSearch
var elasticSearchLogger = ElasticSearchLogger();
// Console logger writes messages to console
var consoleLogger = ConsoleLogger();
# ElasticSearchLogger sends a log to ElasticSearch
elasticsearch_logger: ElasticSearchLogger = ElasticSearchLogger()
# Console logger writes messages to console
console_logger: ConsoleLogger = ConsoleLogger()
Once these instances have been created, we can configure them. To address this, we create a common configuration object that contains all the necessary parameters and their values:
let config = ConfigParams.fromTuples(
// Common config
"source", "my_component_log",
"level", LogLevel.Debug,
// Elastic config
"index", "log",
"daily", true,
"date_format", "YYYYMMDD",
"connection.host", "localhost",
"connection.port", 9200,
"connection.protocol", "http",
);
var config = ConfigParams.FromTuples(
// Common config
"source", "my_component_log",
"level", LogLevel.Debug,
// Elastic config
"index", "log",
"daily", true,
"date_format", "yyyyMMdd",
"connection.host", "localhost",
"connection.port", 9200,
"connection.protocol", "http",
);
config := cconf.NewConfigParamsFromTuples(
// Common config
"source", "my_component_log",
"level", clog.Debug,
// Elastic config
"index", "log",
"daily", true,
"date_format", "yyyyMMdd",
"connection.host", "localhost",
"connection.port", 9200,
"connection.protocol", "http",
)
var config = ConfigParams.fromTuples([
// Common config
'source', 'my_component_log',
'level', LogLevel.Debug,
// Elastic config
'index', 'log',
'daily', true,
'date_format', 'yyyyMMdd',
'connection.host', 'localhost',
'connection.port', 9200,
'connection.protocol', 'http',
]);
config = ConfigParams.from_tuples(
# Common config
'source', 'my_component_log',
'level', LogLevel.Debug,
# Elastic config
'index', 'log',
'daily', True,
"date_format", 'YYYYMMDD',
'connection.host', 'localhost',
'connection.port', 9200,
"connection.protocol", "http",
)
and we assign these values to the respective objects
elasticSearchLogger.configure(config);
await elasticSearchLogger.open("123");
elasticSearchLogger.Configure(config);
elasticSearchLogger.OpenAsync("123").Wait();
elasticSearchLogger.Configure(context.Background(), config)
_ = elasticSearchLogger.Open(context.Background(), "123")
elasticSearchLogger.configure(config);
await elasticSearchLogger.open('123');
elasticsearch_logger.configure(config)
elasticsearch_logger.open("123")
Next, we connect our ElasticSearch logger:
consoleLogger.configure(config);
consoleLogger.Configure(config);
consoleLogger.Configure(context.Background(), config)
consoleLogger.configure(config);
console_logger.configure(config)
Composite logger
After defining our two loggers, we define a composite logger that manages both. For this, we first declare a reference object that points to both loggers:
let references = References.fromTuples(
new Descriptor("my-component", "logger", "console", "default", "1.0"), elasticSearchLogger,
new Descriptor("my-component", "logger", "elasticsearch", "default", "1.0"), consoleLogger
);
var references = References.FromTuples(
new Descriptor("my-component", "logger", "console", "default", "1.0"), elasticSearchLogger,
new Descriptor("my-component", "logger", "elasticsearch", "default", "1.0"), consoleLogger
);
references := cref.NewReferencesFromTuples(context.Background(),
cref.NewDescriptor("my-component", "logger", "console", "default", "1.0"), elasticSearchLogger,
cref.NewDescriptor("my-component", "logger", "elasticsearch", "default", "1.0"), consoleLogger,
)
var references = References.fromTuples([
Descriptor('my-component', 'logger', 'console', 'default', '1.0'),
elasticSearchLogger,
Descriptor('my-component', 'logger', 'elasticsearch', 'default', '1.0'),
consoleLogger
]);
references = References.from_tuples(
Descriptor('my-component', 'logger', 'console', 'default', '1.0'), elasticsearch_logger,
Descriptor('my-component', 'logger', 'elasticsearch', 'default', '1.0'), console_logger
)
Then, we create an instance of the CompositeLogger class:
let logger = new CompositeLogger();
var logger = new CompositeLogger();
logger := clog.NewCompositeLogger()
var logger = CompositeLogger();
logger = CompositeLogger()
And, we add our references to it:
logger.setReferences(references);
logger.SetReferences(references);
logger.SetReferences(context.Background(), references)
logger.setReferences(references);
logger.set_references(references)
Adding log messages:
Now that our structure is complete, we can create different log messages, which will be sent to ElasticSearch and the console after executing our code:
logger.info("123", "Composite logger is configured and ready for using");
logger.warn("123", "Example warning");
logger.error("123", new Error("Example error"), "Error message");
logger.debug("123", "Debug info");
logger.fatal("123", new Error("Fatal error"), "Error that crash the process");
logger.Info("123", "Composite logger is configured and ready for using");
logger.Warn("123", "Example warning");
logger.Error("123", new Exception("Example error"), "Error message");
logger.Debug("123", "Debug info");
logger.Fatal("123", new Exception("Fatal error"), "Error that crash the process");
logger.Info(context.Background(), "123", "Composite logger is configured and ready for using")
logger.Warn(context.Background(), "123", "Example warning")
logger.Error(context.Background(), "123", errors.New("Example error"), "Error message")
logger.Debug(context.Background(), "123", "Debug info")
logger.Fatal(context.Background(), "123", errors.New("Fatal error"), "Error that crash the process")
logger.Info("123", "Composite logger is configured and ready for using");
logger.Warn("123", "Example warning");
logger.Error("123", new Exception("Example error"), "Error message");
logger.Debug("123", "Debug info");
logger.Fatal("123", new Exception("Fatal error"), "Error that crash the process");
logger.info("123", "Composite logger is configured and ready for using")
logger.warn("123", "Example warning")
logger.error("123", Exception("Example error"), "Error message")
logger.debug("123", "Debug info")
logger.fatal("123", Exception("Fatal error"), "Error that crash the process")
After code execution, the following messages will appear on our console:
And, we can see the ElasticSearch messages by using the URL:
http://localhost:9200/index_name/_search?pretty
where index_name is is “log” + “-” + current date (in date_format from config params).
For example, for January 25, 2022, our URL is
http://localhost:9200/log-20220125/_search?pretty
which will show:
Code Example
{
"took" : 3,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 5,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "log-20220127",
"_type" : "_doc",
"_id" : "10399e390171415ca122dbb307f67eea",
"_score" : 1.0,
"_source" : {
"time" : "2022-01-26T23:12:01.954Z",
"level" : "INFO",
"source" : "my_component_log",
"correlation_id" : "123",
"error" : null,
"message" : "Composite logger is configured and ready for using"
}
},
{
"_index" : "log-20220127",
"_type" : "_doc",
"_id" : "ed1d25a2051c444783f4539861dd44f1",
"_score" : 1.0,
"_source" : {
"time" : "2022-01-26T23:12:01.956Z",
"level" : "WARN",
"source" : "my_component_log",
"correlation_id" : "123",
"error" : null,
"message" : "Example warning"
}
},
{
"_index" : "log-20220127",
"_type" : "_doc",
"_id" : "0cc6fdd3d16447e6a9fa5f0ec111edc9",
"_score" : 1.0,
"_source" : {
"time" : "2022-01-26T23:12:01.957Z",
"level" : "ERROR",
"source" : "my_component_log",
"correlation_id" : "123",
"error" : {
"type" : "Error",
"category" : "Unknown",
"status" : 500,
"code" : "UNKNOWN",
"message" : "Example error",
"stack_trace" : "Error: Example error\n at C:\\Users\\user1\\OneDrive\\Desktop\\examples\\node\\obj\\elastic.js:35:29\n at Generator.next (<anonymous>)\n at fulfilled (C:\\Users\\user1\\OneDrive\\Desktop\\examples\\node\\obj\\elastic.js:5:58)"
},
"message" : "Error message"
}
},
{
"_index" : "log-20220127",
"_type" : "_doc",
"_id" : "039cf650b46b4ca49c513df617055dc3",
"_score" : 1.0,
"_source" : {
"time" : "2022-01-26T23:12:01.958Z",
"level" : "DEBUG",
"source" : "my_component_log",
"correlation_id" : "123",
"error" : null,
"message" : "Debug info"
}
},
{
"_index" : "log-20220127",
"_type" : "_doc",
"_id" : "7f8e1ef9a82643f382cffa52f9110ce3",
"_score" : 1.0,
"_source" : {
"time" : "2022-01-26T23:12:01.959Z",
"level" : "FATAL",
"source" : "my_component_log",
"correlation_id" : "123",
"error" : {
"type" : "Error",
"category" : "Unknown",
"status" : 500,
"code" : "UNKNOWN",
"message" : "Fatal error",
"stack_trace" : "Error: Fatal error\n at C:\\Users\\user1\\OneDrive\\Desktop\\examples\\node\\obj\\elastic.js:37:29\n at Generator.next (<anonymous>)\n at fulfilled (C:\\Users\\user1\\OneDrive\\Desktop\\examples\\node\\obj\\elastic.js:5:58)"
},
"message" : "Error that crash the process"
}
}
]
}
}
Code Example
{
"took" : 5,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 5,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "log-20220125",
"_type" : "_doc",
"_id" : "8cd3ef625b804ffdb995827e59bac01f",
"_score" : 1.0,
"_source" : {
"correlation_id" : "123",
"error" : null,
"level" : 4,
"message" : "Composite logger is configured and ready for using",
"source" : null,
"time" : "2022-01-25T17:47:53.274931"
}
},
{
"_index" : "log-20220125",
"_type" : "_doc",
"_id" : "e636b3a8b76e44cabea31e9e92f0b451",
"_score" : 1.0,
"_source" : {
"correlation_id" : "123",
"error" : null,
"level" : 3,
"message" : "Example warning",
"source" : null,
"time" : "2022-01-25T17:47:53.274931"
}
},
{
"_index" : "log-20220125",
"_type" : "_doc",
"_id" : "144d963d95c74b4a84e1558dde3704f9",
"_score" : 1.0,
"_source" : {
"correlation_id" : "123",
"error" : {
"category" : "Unknown",
"cause" : null,
"code" : "UNKNOWN",
"correlation_id" : null,
"details" : null,
"message" : "Example error",
"stack_trace" : null,
"status" : 500,
"type" : null
},
"level" : 2,
"message" : "Error message",
"source" : null,
"time" : "2022-01-25T17:47:53.274931"
}
},
{
"_index" : "log-20220125",
"_type" : "_doc",
"_id" : "25226536425246fab9b78a3dca4919fd",
"_score" : 1.0,
"_source" : {
"correlation_id" : "123",
"error" : null,
"level" : 5,
"message" : "Debug info",
"source" : null,
"time" : "2022-01-25T17:47:53.275937"
}
},
{
"_index" : "log-20220125",
"_type" : "_doc",
"_id" : "d49a4fda786241af98638b0d82c93ec9",
"_score" : 1.0,
"_source" : {
"correlation_id" : "123",
"error" : {
"category" : "Unknown",
"cause" : null,
"code" : "UNKNOWN",
"correlation_id" : null,
"details" : null,
"message" : "Fatal error",
"stack_trace" : null,
"status" : 500,
"type" : null
},
"level" : 1,
"message" : "Error that crash the process",
"source" : null,
"time" : "2022-01-25T17:47:53.275937"
}
}
]
}
}
Code Example
{
"took" : 3,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 5,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "log123-20220126",
"_type" : "log_message",
"_id" : "bf18e9659fb043668f8c006d4e9aba26",
"_score" : 1.0,
"_source" : {
"time" : "2022-01-26T23:28:10.0825714Z",
"source" : "my_component_log",
"level" : 4,
"correlation_id" : "123",
"error" : {
"type" : "",
"category" : "",
"status" : 0,
"code" : "",
"message" : "",
"details" : null,
"correlation_id" : "",
"cause" : "",
"stack_trace" : ""
},
"message" : "Composite logger is configured and ready for using"
}
},
{
"_index" : "log123-20220126",
"_type" : "log_message",
"_id" : "25cc4c2c81984a348f640e7435891e2b",
"_score" : 1.0,
"_source" : {
"time" : "2022-01-26T23:28:10.0832355Z",
"source" : "my_component_log",
"level" : 3,
"correlation_id" : "123",
"error" : {
"type" : "",
"category" : "",
"status" : 0,
"code" : "",
"message" : "",
"details" : null,
"correlation_id" : "",
"cause" : "",
"stack_trace" : ""
},
"message" : "Example warning"
}
},
{
"_index" : "log123-20220126",
"_type" : "log_message",
"_id" : "7e671ce009be46078272eae6dcab0328",
"_score" : 1.0,
"_source" : {
"time" : "2022-01-26T23:28:10.0832355Z",
"source" : "my_component_log",
"level" : 2,
"correlation_id" : "123",
"error" : {
"type" : "",
"category" : "Unknown",
"status" : 500,
"code" : "UNKNOWN",
"message" : "Example error",
"details" : null,
"correlation_id" : "",
"cause" : "",
"stack_trace" : ""
},
"message" : "Error message"
}
},
{
"_index" : "log123-20220126",
"_type" : "log_message",
"_id" : "f9879db7638947ab8ae43c475c6d8e78",
"_score" : 1.0,
"_source" : {
"time" : "2022-01-26T23:28:10.0846687Z",
"source" : "my_component_log",
"level" : 5,
"correlation_id" : "123",
"error" : {
"type" : "",
"category" : "",
"status" : 0,
"code" : "",
"message" : "",
"details" : null,
"correlation_id" : "",
"cause" : "",
"stack_trace" : ""
},
"message" : "Debug info"
}
},
{
"_index" : "log123-20220126",
"_type" : "log_message",
"_id" : "4261be380da94e18923f726d60a91bc7",
"_score" : 1.0,
"_source" : {
"time" : "2022-01-26T23:28:10.0846687Z",
"source" : "my_component_log",
"level" : 1,
"correlation_id" : "123",
"error" : {
"type" : "",
"category" : "Unknown",
"status" : 500,
"code" : "UNKNOWN",
"message" : "Fatal error",
"details" : null,
"correlation_id" : "",
"cause" : "",
"stack_trace" : ""
},
"message" : "Error that crash the process"
}
}
]
}
}
Code Example
{
"took" : 7,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 8,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "dart-2022.01.26",
"_type" : "_doc",
"_id" : "cdcbd0d126af43258e23e47e29095edd",
"_score" : 1.0,
"_source" : {
"time" : "2022-01-26T23:53:41.411514Z",
"source" : "my_component_log",
"level" : "FATAL",
"correlation_id" : "123",
"error" : {
"type" : "_Exception",
"category" : "Unknown",
"status" : 500,
"code" : "UNKNOWN",
"message" : "Exception: Fatal error",
"details" : null,
"correlation_id" : null,
"cause" : null,
"stack_trace" : null
},
"message" : "Error that crash the process3"
}
},
{
"_index" : "dart-2022.01.26",
"_type" : "_doc",
"_id" : "ce4d75dfce62408bbf38058f6c7e3f56",
"_score" : 1.0,
"_source" : {
"time" : "2022-01-26T23:54:53.912245Z",
"source" : "my_component_log",
"level" : "INFO",
"correlation_id" : "123",
"error" : null,
"message" : "Composite logger is configured and ready for using"
}
},
{
"_index" : "dart-2022.01.26",
"_type" : "_doc",
"_id" : "1b21d8025bb44bf9ab81dd53a520206c",
"_score" : 1.0,
"_source" : {
"time" : "2022-01-26T23:55:53.197636Z",
"source" : "my_component_log",
"level" : "WARN",
"correlation_id" : "123",
"error" : null,
"message" : "Example warning"
}
},
{
"_index" : "dart-2022.01.26",
"_type" : "_doc",
"_id" : "d5193092586d4264a6845afa7a37c09f",
"_score" : 1.0,
"_source" : {
"time" : "2022-01-26T23:56:08.568801Z",
"source" : "my_component_log",
"level" : "ERROR",
"correlation_id" : "123",
"error" : {
"type" : "_Exception",
"category" : "Unknown",
"status" : 500,
"code" : "UNKNOWN",
"message" : "Exception: Example error",
"details" : null,
"correlation_id" : null,
"cause" : null,
"stack_trace" : null
},
"message" : "Error message"
}
},
{
"_index" : "dart-2022.01.26",
"_type" : "_doc",
"_id" : "1aa58931b5cd448d9b8c21c43efd55a8",
"_score" : 1.0,
"_source" : {
"time" : "2022-01-26T23:56:11.693541Z",
"source" : "my_component_log",
"level" : "DEBUG",
"correlation_id" : "123",
"error" : null,
"message" : "Debug info"
}
},
{
"_index" : "dart-2022.01.26",
"_type" : "_doc",
"_id" : "1148e374c85e4b2c9ebf7f2c28d10189",
"_score" : 1.0,
"_source" : {
"time" : "2022-01-26T23:56:14.664195Z",
"source" : "my_component_log",
"level" : "FATAL",
"correlation_id" : "123",
"error" : {
"type" : "_Exception",
"category" : "Unknown",
"status" : 500,
"code" : "UNKNOWN",
"message" : "Exception: Fatal error",
"details" : null,
"correlation_id" : null,
"cause" : null,
"stack_trace" : null
},
"message" : "Error that crash the process"
}
}
]
}
}
Code Example
{
"took" : 5,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 5,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "log-20220125",
"_type" : "_doc",
"_id" : "8cd3ef625b804ffdb995827e59bac01f",
"_score" : 1.0,
"_source" : {
"correlation_id" : "123",
"error" : null,
"level" : 4,
"message" : "Composite logger is configured and ready for using",
"source" : null,
"time" : "2022-01-25T17:47:53.274931"
}
},
{
"_index" : "log-20220125",
"_type" : "_doc",
"_id" : "e636b3a8b76e44cabea31e9e92f0b451",
"_score" : 1.0,
"_source" : {
"correlation_id" : "123",
"error" : null,
"level" : 3,
"message" : "Example warning",
"source" : null,
"time" : "2022-01-25T17:47:53.274931"
}
},
{
"_index" : "log-20220125",
"_type" : "_doc",
"_id" : "144d963d95c74b4a84e1558dde3704f9",
"_score" : 1.0,
"_source" : {
"correlation_id" : "123",
"error" : {
"category" : "Unknown",
"cause" : null,
"code" : "UNKNOWN",
"correlation_id" : null,
"details" : null,
"message" : "Example error",
"stack_trace" : null,
"status" : 500,
"type" : null
},
"level" : 2,
"message" : "Error message",
"source" : null,
"time" : "2022-01-25T17:47:53.274931"
}
},
{
"_index" : "log-20220125",
"_type" : "_doc",
"_id" : "25226536425246fab9b78a3dca4919fd",
"_score" : 1.0,
"_source" : {
"correlation_id" : "123",
"error" : null,
"level" : 5,
"message" : "Debug info",
"source" : null,
"time" : "2022-01-25T17:47:53.275937"
}
},
{
"_index" : "log-20220125",
"_type" : "_doc",
"_id" : "d49a4fda786241af98638b0d82c93ec9",
"_score" : 1.0,
"_source" : {
"correlation_id" : "123",
"error" : {
"category" : "Unknown",
"cause" : null,
"code" : "UNKNOWN",
"correlation_id" : null,
"details" : null,
"message" : "Fatal error",
"stack_trace" : null,
"status" : 500,
"type" : null
},
"level" : 1,
"message" : "Error that crash the process",
"source" : null,
"time" : "2022-01-25T17:47:53.275937"
}
}
]
}
}
Wrapping up
In this tutorial, we have learned what logging is, the different logging levels, and how to use the ConsoleLogger and CompositeLogger from PIP.Services to display log messages. The main advantage of the composite logger is its capacity to aggregate all logging messages, thus creating a centralized logging point.
We have also learned that PIP.Services provides several implementations of loggers, such as CloudWatchLogger, ElasticSearchLogger, and DataDogLogger.
Although the examples presented here are quite general, the concepts learned continue to apply to the development of more complex applications.