fittinq / logger-elasticsearch
Requires
- php: ^8.1
- elasticsearch/elasticsearch: ^9.0
- psr/log: ^2.0.0
Requires (Dev)
- nyholm/psr7: ^1.8
- phpunit/phpunit: ^9.0
- psr/http-client: ^1.0
- psr/http-message: ^2.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
This library gives a framework to log to ElasticSearch. It has a few concepts that might look weird at first glance.
Connect to ElasticSearch
First we connect to Elasticsearch with the client builder. It takes the host and an API key, and you can set this up in your service.yml as follows
Fittinq\Logger\Elastic\ClientBuilder:
arguments:
- '%env(ELASTIC_LOGGER_HOST)%'
- '%env(ELASTIC_LOGGER_API_KEY)%'
On Elastic Cloud Serverless the host is the project endpoint (https://<project>.es.<region>.elastic.cloud) and the API
key is generated per project. Both arguments are required: Serverless rejects unauthenticated requests, so there is no
longer a no-auth mode to fall back to.
Upgrading to 9.x
The log document moved to the data stream shape:
createdAtis now@timestamp. Data streams require that name, and it must be a mappeddatefield. Saved Kibana searches, dashboards and any query filtering or sorting oncreatedAtneed updating.- Writes use
op_type: create. Data streams accept nothing else. With no document id this behaves exactly like a normal index request against a regular index, so a service still writing to a dated index is unaffected.
Pair this with fittinq/symfony-connector 25.0.0, which wires IndexResolver instead of
DateIndex - a data stream must not carry a -Ymd suffix, because Elasticsearch handles rollover.
Upgrading from 7.x
This version moves from the 7.x Elasticsearch client to 9.x, which is what Elastic supports against Serverless. Three things change for consumers:
ClientBuildernow takes a second, required$apiKeyargument. Every service definition wiring this class must be updated before the service will boot.getClient()returnsElastic\Elasticsearch\Client, notElasticsearch\Client. Type hints and imports in consuming code need the new namespace.- Calls return an
Elasticsearchresponse object instead of an array. It implementsArrayAccess, so$response['_id']keeps working, butis_array()checks and array functions applied to a response do not. UseasArray()if you need a real array.
Note that Elastic\Elasticsearch\Client is final, so it cannot be subclassed in test doubles. Mock the PSR-18 HTTP
client instead and build a real Elasticsearch client on top of it — see tests/ElasticSearch/ClientBuilderMock.php. Any
such double must return an X-Elastic-Product: Elasticsearch response header, or the client rejects the response.
Indices
The ElasticSearch logger must write its message to a given index. Because you might want to decide you want an index by day, or an index by the alphabet we introduced the IndexResolver.
To get you going we added a IndexResolver class that simply names the index by any name that you pass to its constructor. We provided a second resolver called DateIndex which suffixes the given name with the date in yyyymmdd format.
These can be added to your project by wiring them as follows:
Fittinq\Logger\Index\IndexResolver:
arguments:
- 'my_index'
or
Fittinq\Logger\Index\DateIndex:
arguments:
- 'prefix_%env(APP_ENV)%'
- '_Ymd'
Context
When you log a message, you probably might want to add some context. Such as which service initiated the log message. You can provide context where you log the message since PSR-3 supports this. However, this might be inconvenient. You might not have the right data at hand. For instance, you don't want to have every class that logs a message know what the service they're in is called. In fact, you might not even be able to add that to a class if it comes from another library.
We use the ContextResolver for this. You can use this to set up logic that is added to the context every time you log something.
Fittinq\Logger\Context\ContextResolver:
arguments:
- { arg1: 'myvalue', arg2: 'myvalue2' }
Set up the actual logger
Then we tie all pieces together:
Fittinq\Logger\Logger\ElasticSearchLogger:
arguments:
- '@Fittinq\Logger\Elastic\ClientBuilder'
- '@Fittinq\Logger\Index\DateIndex'
- '@Fittinq\Logger\Context\ContextResolver'