Logger Plugin for Swift4
Moderators: Chris Corbyn, General Moderators
-
BrandonMUS
- Forum Newbie
- Posts: 15
- Joined: Mon Nov 10, 2008 9:45 am
Logger Plugin for Swift4
Does anyone have an example plugin for swiftmailer 4? Since the docs are still a WIP, I'm a little unsure about how to approach a logging plugin. I need to log every email that gets sent by my app including all of the headers. I'll then end up using this log to guarantee that emails are not being duplicated and that the email system isn't being abused. I found Swift_Plugins_Logger and Swift_Plugins_LoggerPlugin, but I'm not sure how to properly extend them... I'll be logging to a database.
- Chris Corbyn
- Breakbeat Nuttzer
- Posts: 13098
- Joined: Wed Mar 24, 2004 7:57 am
- Location: Melbourne, Australia
Re: Logger Plugin for Swift4
The logger plugin itself doesn't log the email itself since they can run into several MB each. I'm considering extending it to do this however.
It sounds like you need a simple plugin:
It sounds like you need a simple plugin:
Code: Select all
class YourPlugin implements Swift_Events_SendListener {
public function beforeSendPerformed(Swift_Events_SendEvent $evt) {
}
public function sendPerformed(Swift_Events_SendEvent $evt) {
$message = $evt->getMessage();
$emailSource = $message->toString();
//You now have your .eml file contents to do with them what you please..
}
}
$mailer->registerPlugin(new YourPlugin());-
BrandonMUS
- Forum Newbie
- Posts: 15
- Joined: Mon Nov 10, 2008 9:45 am
Re: Logger Plugin for Swift4
Thanks for the info. It looks pretty simple, so I'll give it a shot today if I get the time!
-
BrandonMUS
- Forum Newbie
- Posts: 15
- Joined: Mon Nov 10, 2008 9:45 am
Re: Logger Plugin for Swift4
Am I missing something? I tried to use the example in the docs:
Here was my error message:
EDIT: Found the problem. In the docs, you walk through the steps, but failed to highlight it again in the code. In the EchoLogger snippet, you do not wrap the logger object in an instance of Swift_Plugins_LoggerPlugins. My updated code is:
And it seems to work without issue.
Just an FYI.
Code: Select all
require_once 'lib/swiftmailer4/swift_required.php';
$emailer = Swift_Mailer::newInstance(Swift_SmtpTransport::newInstance('localhost'));
$emailer->registerPlugin(new Swift_Plugins_Loggers_EchoLogger());Code: Select all
Warning [4096] Argument 1 passed to Swift_Mailer::registerPlugin() must be an instance of Swift_Events_EventListener, instance of Swift_Plugins_Loggers_EchoLogger given, called in /home/httpd/vhosts/.../OT_EmailNotifier.php on line 107 and defined
Error on line 170 in file /home/httpd/vhosts/.../lib/swiftmailer4/classes/Swift/Mailer.php
Warning [4096] Argument 1 passed to Swift_Transport_AbstractSmtpTransport::registerPlugin() must be an instance of Swift_Events_EventListener, instance of Swift_Plugins_Loggers_EchoLogger given, called in /home/httpd/vhosts/.../lib/swiftmailer4/classes/Swift/Mailer.php on line 172 and defined
Error on line 239 in file /home/httpd/vhosts/.../lib/swiftmailer4/classes/Swift/Transport/AbstractSmtpTransport.php
Warning [4096] Argument 1 passed to Swift_Events_SimpleEventDispatcher::bindEventListener() must be an instance of Swift_Events_EventListener, instance of Swift_Plugins_Loggers_EchoLogger given, called in /home/httpd/vhosts/.../lib/swiftmailer4/classes/Swift/Transport/AbstractSmtpTransport.php on line 241 and defined
Error on line 133 in file /home/httpd/vhosts/.../lib/swiftmailer4/classes/Swift/Events/SimpleEventDispatcher.phpCode: Select all
$logger = new Swift_Plugins_Loggers_EchoLogger();
$emailer->registerPlugin(new Swift_Plugins_LoggerPlugin($logger));Just an FYI.
- Chris Corbyn
- Breakbeat Nuttzer
- Posts: 13098
- Joined: Wed Mar 24, 2004 7:57 am
- Location: Melbourne, Australia
Re: Logger Plugin for Swift4
Ouch, sorry, I'll fix the docs.
-
BrandonMUS
- Forum Newbie
- Posts: 15
- Joined: Mon Nov 10, 2008 9:45 am
Re: Logger Plugin for Swift4
So I'm a little confused and I'm not sure the best way to do this. I'm trying to instill a fair amount of logging into this email system (as I think any email system should), and Im' running into some issues that seem to stem from the overly simplistic Swift_Mailer class.
First, I wanted to keep a record of the server (ala Swift_Plugins_LoggerPlugin) so that in the event of a send failure, I would hopefully be able to gain some added insight (beyond just the failed recipients list). Unfortunately, what I found was that after I registered the plugin, there was no way to get back to it. This is solved by storing the instance in a separate variable, but now I would have to inject it as a dependency to other objects if they need to use it. Doable, just annoying. I'm a little suprised to not see a plugin container so that we could get access back to the patterns (eg. Swift_Mailer::getPlugin('plugin_name');) or something. On that same topic, unregisterPlugin()?
Secondly, there is no way to troubleshoot a send without already having a SendListener in place. There are some simple checks I want to know after a send fails like: Was it manually cancelled (bubbleCancelled)? Was there a partial send or is it still queued (getResult)? If it was a partial send, who received it (technically I could compare my failed recipients to the expected recipients I guess, but that makes me get back into Swift_Message which wouldn't account for any event listeners)?
Maybe I'm missing the concept, but I couldn't find an easy way to accomplish what I thought would be fairly straight forward. Just my $.02
First, I wanted to keep a record of the server (ala Swift_Plugins_LoggerPlugin) so that in the event of a send failure, I would hopefully be able to gain some added insight (beyond just the failed recipients list). Unfortunately, what I found was that after I registered the plugin, there was no way to get back to it. This is solved by storing the instance in a separate variable, but now I would have to inject it as a dependency to other objects if they need to use it. Doable, just annoying. I'm a little suprised to not see a plugin container so that we could get access back to the patterns (eg. Swift_Mailer::getPlugin('plugin_name');) or something. On that same topic, unregisterPlugin()?
Secondly, there is no way to troubleshoot a send without already having a SendListener in place. There are some simple checks I want to know after a send fails like: Was it manually cancelled (bubbleCancelled)? Was there a partial send or is it still queued (getResult)? If it was a partial send, who received it (technically I could compare my failed recipients to the expected recipients I guess, but that makes me get back into Swift_Message which wouldn't account for any event listeners)?
Maybe I'm missing the concept, but I couldn't find an easy way to accomplish what I thought would be fairly straight forward. Just my $.02
- Chris Corbyn
- Breakbeat Nuttzer
- Posts: 13098
- Joined: Wed Mar 24, 2004 7:57 am
- Location: Melbourne, Australia
Re: Logger Plugin for Swift4
Hi Brandon,
My original design had ways to get the plugin back out via getPlugin() but I removed it in the interest of simplicity since as you say, you just need to store it in a variable, in just the same way you'd have to store the Transport in a variable if you want a copy of that. I hadn't realised this would cause so much of a problem. I can re-evaluate that decision if it's really not workable.
Do you have a use case for unregisterPlugin()? This was another feature that I considered unneeded in the interest of simplicity, but it would be easy for me to add (it would just accept the plugin as a parameter). All the plugins finish up inside a shared instance of the Swift_Events_EventDispatcher class (which is basically the Plugin container you were looking for).
Again, the reason there's no way to get high-level debugging information without having a SendListener (a plugin for anybody else reading this) in place was in the interest of simplicity (and memory use). Each Transport takes a different approach to sending the email so the Mailer class itself can't make any assumptions there. What sort of interface would you envisage that I should have included? I'll consider it
If a send fails, it's failed. There's no such thing as it being "still queued" within Swift Mailer itself. If your code adds this functionality then you'd have to account for that with some custom coding. If it was manually cancelled the bubbleCancelled() will return true. You can work out who received it as you mention, but comparing the failed recipients list with the recipients that were being sent to.
Is the library presenting you with a brick wall here? It sounds as though you're able to do what you need, you're just unhappy that it's not a "drop in" solution for this high-level logging?
If you provide some specific information (requirements of what exactly you'd be logging and where you'd be storing it) we can work through writing a plugin here, perhaps with the intention of including it in the library.
I had considered writing a DebuggerTransport that acts as a wrapper around the actual Transport, though I think it would have been confusing having such a thing in addition to the logger.
My original design had ways to get the plugin back out via getPlugin() but I removed it in the interest of simplicity since as you say, you just need to store it in a variable, in just the same way you'd have to store the Transport in a variable if you want a copy of that. I hadn't realised this would cause so much of a problem. I can re-evaluate that decision if it's really not workable.
Do you have a use case for unregisterPlugin()? This was another feature that I considered unneeded in the interest of simplicity, but it would be easy for me to add (it would just accept the plugin as a parameter). All the plugins finish up inside a shared instance of the Swift_Events_EventDispatcher class (which is basically the Plugin container you were looking for).
Again, the reason there's no way to get high-level debugging information without having a SendListener (a plugin for anybody else reading this) in place was in the interest of simplicity (and memory use). Each Transport takes a different approach to sending the email so the Mailer class itself can't make any assumptions there. What sort of interface would you envisage that I should have included? I'll consider it
If a send fails, it's failed. There's no such thing as it being "still queued" within Swift Mailer itself. If your code adds this functionality then you'd have to account for that with some custom coding. If it was manually cancelled the bubbleCancelled() will return true. You can work out who received it as you mention, but comparing the failed recipients list with the recipients that were being sent to.
Is the library presenting you with a brick wall here? It sounds as though you're able to do what you need, you're just unhappy that it's not a "drop in" solution for this high-level logging?
If you provide some specific information (requirements of what exactly you'd be logging and where you'd be storing it) we can work through writing a plugin here, perhaps with the intention of including it in the library.
I had considered writing a DebuggerTransport that acts as a wrapper around the actual Transport, though I think it would have been confusing having such a thing in addition to the logger.
Code: Select all
$mailer = new Swift_Mailer(new Swift_DebuggerTransport(new Swift_SmtpTransport(...)));-
BrandonMUS
- Forum Newbie
- Posts: 15
- Joined: Mon Nov 10, 2008 9:45 am
Re: Logger Plugin for Swift4
I only call it a problem because it makes it harder to add this type of checking as an after thought. If I know that down the road something in my system will need access to the plugins (I'm sticking with my debug/listener plugin for now), I have to plan ahead and inject that plugin reference to every class until I get to the point where it is needed. My emailer is only two classes, so it is relatively easy for me to implement, but if someone was using this in a more complex newsletter system, I could see it getting messy. IMO, an ideal solution would have it stored in the Swift_Mailer instance somehow with a public method like Swift_Mailer::getPlugin('plugin_name'); or something. How the plugins are reigsted would probably also need to be altered so that we can name plugins (or it could just default to the plugin class name maybe?).Chris Corbyn wrote:My original design had ways to get the plugin back out via getPlugin() but I removed it in the interest of simplicity since as you say, you just need to store it in a variable, in just the same way you'd have to store the Transport in a variable if you want a copy of that. I hadn't realised this would cause so much of a problem. I can re-evaluate that decision if it's really not workable.
Nah, I can't see any reason that it would be needed, I was just thinking out loud.Chris Corbyn wrote:Do you have a use case for unregisterPlugin()? This was another feature that I considered unneeded in the interest of simplicity, but it would be easy for me to add (it would just accept the plugin as a parameter). All the plugins finish up inside a shared instance of the Swift_Events_EventDispatcher class (which is basically the Plugin container you were looking for).
I got the "still queued" idea from the Swift_Events_SendEvent Result_ constants. I know that the transports I use will only ever come back as Success, Tentative or Failure, but I was just using it as an example of extra information that is out there, just not readily accessible. As for the bubbleCancelled, I think this is a very important thing for debugging. If you have an event listener that manually cancelled the send, I think it's important to be able to tell. A cancelled send isn't a big deal, but an unhandled failure is bad and I would want to know about it.Chris Corbyn wrote:Again, the reason there's no way to get high-level debugging information without having a SendListener (a plugin for anybody else reading this) in place was in the interest of simplicity (and memory use). Each Transport takes a different approach to sending the email so the Mailer class itself can't make any assumptions there. What sort of interface would you envisage that I should have included? I'll consider it
If a send fails, it's failed. There's no such thing as it being "still queued" within Swift Mailer itself. If your code adds this functionality then you'd have to account for that with some custom coding. If it was manually cancelled the bubbleCancelled() will return true. You can work out who received it as you mention, but comparing the failed recipients list with the recipients that were being sent to.
It's not so much a brick wall (as I found the workaround fairly quickly) but more of a heads-up. Really, the part I don't like is that I have to rely on a plugin to debug my sends. I would much rather be able to do the debugging in the same spot I do the sending in my application. I really don't know what the interface would look like, but the ability to get to the Swift_Send_Event would be idealChris Corbyn wrote:Is the library presenting you with a brick wall here? It sounds as though you're able to do what you need, you're just unhappy that it's not a "drop in" solution for this high-level logging?
Code: Select all
try{
//getEmailer returns Swift_Mailer
$this->getEmailer()->send(...);
catch (Swift_Exception $swift_e) {
//$this->getEmailer()->getSendEvent(); //returns Swift_Send_Event just like a plugin receives; and would return null if send wasn't attempted yet
}The plugin architecture seems solid. I didn't have any problems digging the information I needed out of the Swift_Send_Event object, I was just uneasy? with where the logic had to go.Chris Corbyn wrote:If you provide some specific information (requirements of what exactly you'd be logging and where you'd be storing it) we can work through writing a plugin here, perhaps with the intention of including it in the library.
I had considered writing a DebuggerTransport that acts as a wrapper around the actual Transport, though I think it would have been confusing having such a thing in addition to the logger.
Code: Select all
$mailer = new Swift_Mailer(new Swift_DebuggerTransport(new Swift_SmtpTransport(...)));
About the only thing I didn't see the ability to access in my SendListener is my ArrayLogger plugin. In an ideal world, I would attach the complete log of communication, but I can live without it.