In my opinion, Monolog is more configurable, as you can add handlers, processors, and formatters to fulfill any requirement. Probably it's also more efficient because it is more low level (using services instead of Drupal plugins).
I agree with you that Monolog is best suited for more complex cases.
If you can add Monolog as an alternative to Logger, it's OK for me.
Thanks for this constructive conversation :-)
Yes, Monolog is able to log custom metadata. Just install the module, then add this line to settings.php:
$settings['container_yamls'][] = 'sites/default/monolog.service.yml';
And this content into sites/default/monolog.service.yml:
parameters:
monolog.channel_handlers:
default: ['rotating_file']
services:
monolog.handler.rotating_file:
class: Monolog\Handler\RotatingFileHandler
arguments: ['private://logs/debug.log', 10, 'DEBUG']
Now, add this instruction to an example controller:
$this->getLogger('example')->info(
message: 'Lorem ipsum',
context: [
'any' => [
'structured' => [
'data' => 'here',
],
],
],
);
Monolog will log a line into private://logs/debug.log like:
[2025-11-01T19:35:01.088601+01:00] example.INFO: Lorem ipsum {"any":{"structured":{"data":"here"}}} {"referer":"","ip":"172.20.0.7","request_uri":"https://drupal-cms.ddev.site:33001/drupalcon2024/sync","uid":"1","user":"admin"}
Where "Lorem ipsum" is the message, "{"any":{"structured":{"data":"here"}}}" is the context metadata added to the log and "{"referer":"","ip":"172.20.0.7","request_uri":"https://drupal-cms.ddev.site:33001/example","uid":"1","user":"admin"}" are provided by Monolog Processors (some already provided by the module: https://git.drupalcode.org/project/monolog/-/tree/3.0.x/src/Logger/Proce..., but you can add as many custom processors as you want: https://git.drupalcode.org/project/monolog/-/blob/3.0.x/README.md?ref_ty...).
You can also use Monolog to log to the database:
parameters:
monolog.channel_handlers:
default:
handlers:
- name: 'drupal.dblog'
In that case, of course, the context metadata gets lost because the watchdog table doesn't have room for it. To address this, we can add a processor like:
public function __invoke(LogRecord $record): LogRecord {
if ($record->context === []) {
return $record;
}
return $record->with(message: $record['message'] . ' | Context: ' . json_encode($record['context']));
}
to append the context to the message.
Yes, I know :-(.
It was a straight port of the LLPhant DocumentSplitter class, but it has never been touched since then.
The problem here is that AI search is doing way more than a Typesense user needs, so it seems strange to add a dependency on it. A solution could be to move the chunking plugins into the AI module itself.
lussoluca → created an issue. See original summary → .
I'm working on integrating symfony/amazon-sqs-messenger for a customer project, and I'm wondering if we are not overcomplicating things here.
All that is required to add a new transport is registering its factory in the service provider:
final class SmServiceProvider implements ServiceProviderInterface {
public function register(ContainerBuilder $container): void {
[...]
if(\class_exists(AmazonSqsTransportFactory::class)) {
$container
->register(AmazonSqsTransportFactory::class, AmazonSqsTransportFactory::class)
->setPublic(FALSE);
}
if(\class_exists(RedisTransportFactory::class)) {
$container
->register(RedisTransportFactory::class, RedisTransportFactory::class)
->setPublic(FALSE);
}
}
}
And then add the transport DSN in a custom messages.services.yml:
parameters:
sm.routing:
Drupal\my_module\AsyncExampleMessage: sqs
sm.transports:
redis:
dsn: 'redis://redis:6379/messages'
synchronous:
dsn: 'sync://'
asynchronous:
dsn: 'drupal-sql://default'
failed:
dsn: 'drupal-sql://default?queue_name=failed'
sqs:
dsn: 'https://sqs.eu-north-1.amazonaws.com/1234567890/messages'
Having a transport DSN defined in a services.yml of a custom module is not so useful, because users will change its value in nearly all cases.
Take, for example, the Redis DSN, it will not be redis://localhost:6379/messages in any production environment, so users will have to override it in a custom messages.services.yml file in any case.
I propose to add all the Symfony-provided transports as optional services in SmServiceProvider (like the example before), and get rid of separate modules.
lussoluca → made their first commit to this issue’s fork.
I would like to opt for these projects:
*
https://www.drupal.org/project/webprofiler →
(issues are now on gitlab.com and not on drupal.org, I'll migrate them by myself)
*
https://www.drupal.org/project/monolog →
Thanks
lussoluca → made their first commit to this issue’s fork.
lussoluca → made their first commit to this issue’s fork.
lussoluca → made their first commit to this issue’s fork.
Implementing the messenger:failed:retry command, I've found that the findAll method must use a query like the one in the get method, otherwise it will return messages that have been successfully retried.
I've tested the feature and it works as expected
Can you please try with the new 1.1.0 release → ?
lussoluca → made their first commit to this issue’s fork.
lussoluca → created an issue.
valthebald → credited lussoluca → .
A new Plugin type named AiGuardrail is added to define guardrails implementation. A guardrail plugin should implement ConfigurableInterface and PluginFormInterface from Core (to make the plugin configurable by a form). A new interface is created to mark plugins that need access to the AiPluginManager service: NeedsAiPluginManagerInterface.
An
AiGuardrail
plugin must implement the processInput method that takes a ChatInput as input and returns a GuardrailResultInterface. The AI module provides some implementation for the
GuardrailResultInterface
:
PassResult: indicates the input can pass without changesStopResult: indicates the input should not be processed further (and a standard message has to be sent to the user)RewriteInputResult: indicates the input should be rewritten (maybe to remove some PII)RewriteOutputResult: indicates the output should be rewritten (maybe to remove unwanted information from a LLM response)
A new configuration entity named ai_guardrail is added, including an ID, label, description, the AiGuardrail plugin to use, and the plugin settings.
An AiGuardrailForm class is provided to render an AiGuardrail plugin form and to save the results as an AiGuardrail entity.
A single guardrail is usually insufficient to protect a conversation between users and an LLM. We want some guardrails to run on the chat input and some others to run on the LLM response, before sending the text to the user. To represent this standard behaviour, a new ai_guardrail_set configuration entity is added, including an ID, label, description, a list of guardrails plugins that must be run before sending the prompt to an LLM (pre_generate_guardrails), and a list of guardrails plugins that must be run after a response from an LLM is received (post_generate_guardrails). An AiGuardrailSetForm class is provided to create and configure a guardrail set with a UI.
Guardrails checks run in an event subscriber, configured to listen to ai.pre_generate_response and ai.post_generate_response events.
An initial integration with the AI module is provided in the chat_generator AiApiExplorer plugin: a new select is added to the Advanced accordion that can be used to choose which ai_guardrail_set to use.
See the attached screen recording for a demo of the UI.
valthebald → credited lussoluca → .
Thanks
lussoluca → made their first commit to this issue’s fork.
Since guardrails can appear in many places such as automators, agents, tools, content suggestions, CKEditor, etc. we need a list of configuration UIs where the functionality can be added. Best would be with screenshots as we might need UX work to create a pleasant configuration experience.
I agree with you, maybe we should open a separate issue for the UI part?
Merged. Thanks!
Thanks!
lussoluca → made their first commit to this issue’s fork.
But please, please, leave the `name` element out of the config.yaml so you don't have the weird project name in there. It's far better IMO for it to take the name from the enclosing directory.
Latest config.yaml is correct, right?
Thanks, Christoph.
That MR is for the version without DDEV committed. Then there is this one for the version with DDEV committed.
Feel free to review it as well, if you have time.
lussoluca → changed the visibility of the branch 3518963-meta-create-the to hidden.
lussoluca → changed the visibility of the branch 3518963-meta-create-the to active.
Meanwhile, I came up with a possible solution.
See the readme here: https://git.drupalcode.org/project/sm/-/merge_requests/43/diffs#8ec9a00b...
It's a super draft implementation (poor naming, no docs, ...), just to see if this approach can fix your issue.
@dpi can you share the WIP you're working on for the redis transport?
Sorry, I wanted to push an initial stub, but then I realized that this issue was opened into ai_agents module (I worked on the ai module...)
I think that guardrails are a generic concept that can be applied to every interaction with an LLM, not only when using agents. Maybe we should move this issue to the ai project?
lussoluca → changed the visibility of the branch 3518963-meta-create-the to hidden.
lussoluca → changed the visibility of the branch 3518963-meta-create-the to active.
lussoluca → changed the visibility of the branch 3518963-meta-create-the to hidden.
lussoluca → made their first commit to this issue’s fork.
@andrewbelcher, this is an interesting approach!
I'm pushing a new MR (https://git.drupalcode.org/project/ai/-/merge_requests/762) with ddev-drupal-contrib artifacts committed and a new command that uses composer require to add a new module to the codebase (similar to ddev poser), for now it is called ai-get-module.
After setting up an environment:
- clone ai module
- ddev start
- ddev poser
- ddev symlink-project
If I want to add ai_agents (as a git cloned repo) to work on it, I can run:
ddev ai-get-module drupal/ai_agents:1.1.x-dev@dev from-source
If I just need the module:
ddev ai-get-module drupal/ai_agents:1.1.1
valthebald → credited lussoluca → .
https://github.com/ddev/ddev-drupal-contrib is a very good project and I've used it in all my contrib modules (monolog, webprofiler, ...).
We need to think about pros and cons (in my opinion):
Pros:
- Well maintained
- Parity with Drupal's CI testing
Cons:
ddev-drupal-contribsuppose you clone only one project at a time. At the moment, cloning multiple modules is not supported (you have to do it manually, by going intoweb/modules/contriband run agit clone)- if you need some other modules (not the source, just to be installed), you can't, unless they're listed in the
requireorrequire-devsection of the module'scomposer.json ddev-drupal-contribworks better if you commit all the DDEV artifacts it creates. The AI ecosystem is huge, here we're thinking about the AI module, but then we should configure every other module in the same way- If we commit DDEV artifacts created by
ddev-drupal-contrib, then we have to maintain them (update them every time they change on the source add-on)
Of course, we can find a way to resolve all those issues, but I think that, in the end, this solution will be more complex to maintain and provide a worse DX.
For example, one request from Marcus was:
Its very common that you do not just work on the AI module, but also some contrib module. It would make it easier if I for instance want to work on the OpenAI provider that it gets it from repo sources, so you don't have to uninstall, git clone and reinstall it
The solution proposed in this MR resolves all the issues and will allow us to release new versions of the stack without the need to release a new version of the AI module.
Just to recap, my proposal is:
- Develop a new generic DDEV add-on (that can be used by any contrib modules) that simplifies contributing to multiple modules at the same time: https://github.com/lussoluca/ddev-drupal-suite
- Develop a new specific DDEV add-on with all the components required by the AI ecosystem (vector db, ffmpeg, ...): https://github.com/lpeabody/ddev-ai
- Develop a Drupal recipe that installs and configures a minimal set of modules: https://www.drupal.org/project/ai_dev_recipe →
- Add to this repo (and maybe the repo of every other AI module) a CONTRIBUTING.md file with a set of instructions
In the end, for me, it's the same. I'll let Marcus and the community decide :-)
Thanks!
lussoluca → made their first commit to this issue’s fork.
@lpeabody cool,
We can add the instruction to apply the DDEV AI add-on here: https://git.drupalcode.org/project/ai/-/merge_requests/745/diffs#3f454a9...
lussoluca → created an issue.
I came up with a solution that is more maintainable and powerful (and more in line with what Randy says).
I created a new DDEV add-on for that, but it's designed to be used by every contrib module, not only by the ai module: https://github.com/lussoluca/ddev-drupal-contrib-root (of course, the namespace is temporary; we can place it where we want).
With this new add-on, the only change in the ai module is a CONTRIBUTING.md file: https://git.drupalcode.org/project/ai/-/merge_requests/745/diffs
Pros:
- No need to commit anything in this repo, we can update the stack without the need for a new AI release
- Support for working on multiple modules. Useful when a dev needs to work on both
aiandai_agentsat the same time (for example) - Support for adding temporary modules or recipes without impacting the
composer.jsonfile of theaimodule - We can then write a specific DDEV add-on to support specific use-cases, like the need for a vector database
I've to finish it, but I think this can be the solution.
Very good solution, thanks
lussoluca → made their first commit to this issue’s fork.
I've added the nullable type hint everywhere is needed
lussoluca → made their first commit to this issue’s fork.
Thanks!
I think that we have to decide which pattern we want to implement:
- AI module in the root and then symlinked to
web/custom, like https://github.com/ddev/ddev-drupal-contrib - Drupal in the root and AI module cloned into
web/custom, like https://github.com/drupal-xb/ddev-drupal-xb-dev
At first, I thought that the first pattern was the one the community was going towards (for example, the Devel module uses it).
However, it is more complex to maintain and adds several unrelated files to the project. So now I'm more in favor of the second.
We can develop a new addon, like ddev-drupal-ai-dev, and add a CONTRIBUTING.md file to this repo. explaining how to use it.
lussoluca → created an issue.
Now, a non-admin key can be used to configure the integration. Of course, the key must have at least access to manage the collection(s) and the documents.
I've prepared a quick recording of a first draft implementation to check if I'm in the right direction.
I'm using the drupal_cms_ai recipe, but maybe it's too much; should we create an ad hoc recipe for this task?
(I still have to check why I have a PHPUnit failure...)
I think that https://github.com/ddev/ddev-drupal-contrib can be a good starting point for this issue.
Then we can add all required ddev addons and initial packages.
Finally, we need a way to install Drupal and install the required recipes
I can work on it :-)
I've removed the sm_test_rate_limiter submodule, and I've added a section in the readme about how to configure the rate limiter
I don't know how to create a MR from here that has the same commits as https://git.drupalcode.org/project/sm/-/merge_requests/33
Anyway, the last commit from https://git.drupalcode.org/project/sm/-/merge_requests/37 is the one you need to fix the issues.
MR https://git.drupalcode.org/project/sm/-/merge_requests/36 is ready to be reviewed
lussoluca → created an issue.
Yes, I saw the announcement. After the #3531660: Drupal SQL/rate limiter/retry-failed/command iteration, I can work on it.
It is one of the missing pieces to replace the core's Queue API (and the advanced queue → module)
It seems that I don't have write permissions to drupal-sql branch.
I've created a new fork with the code from drupal-sql where I can add my commits (https://git.drupalcode.org/project/sm/-/merge_requests/36)
I've lowered the PHPStan level to 5 for now.
During the development of other issues, I'll slowly fix all the level 8 issues, and only after they're fixed, I'll raise the level to 8 again.
Yes, the failure and retry feature of sm (with MR 33) covers all the features from the dead_letter_queue module (and more, as sm works with many queue engines other than SQL database).
Those two issues are about improving the facets options on the test search page we currently have in the backend:
- https://www.drupal.org/project/search_api_typesense/issues/3526693 ✨ Facet labels and other schema settings Active
- https://www.drupal.org/project/search_api_typesense/issues/3526700 ✨ Toggle facets Active
I don't plan on improving that search page much beyond the current version. Instead, we can use those ideas for the frontend block.
What do you think?
Merged! Thanks!
Merged to 1.0.x-dev, thanks!
I'll release a new version of the module later this week
lussoluca → created an issue.
dpi → credited lussoluca → .
Thanks for the MR Pieter, very good solution!
I've added the check for null schema in two more places, please review my commit
lussoluca → made their first commit to this issue’s fork.
This is probably because services autowiring is not yet a common pattern among Drupal developers :-)
I think this should also be backported to D10. Should I open a new issue or a new merge request?
lussoluca → created an issue.
This MR also contains code from ✨ Implement retry Active because it needs support for async transports
lussoluca → created an issue.