-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add new Slack handlers using Slackbot and webhooks #846
Conversation
I will Test it tomorrow and give you Feedback. |
This seems fine to me implementation wise, if you can write tests for SlackRecord at least that'd be nice, testing the curl calls isn't really easy nor worth it IMO. I'd also be happy to get feedback from people actually using this.. :) |
BTW it might be worth looking at this at the same time if the Slack stuff gets a rewrite.. #745 And also marking the original SlackHandler as deprecated would be good I think (I will remove it from master/2.0 then), or do you think there is really a point in having 3? |
I know that this might be a case for all handlers, not just this one, but what if I have disabled curl extension? There is also way to send requests through |
@Seldaek I've started working on the tests and while doing so I've deprecated a couple of protected methods in @greeny Could you point me to Monolog handlers which employ either |
@hkdobrev I did not check monolog for handlers, but I think many of them are firing requests through curl. Guzzle is fine solution, I was just asking, if servers without curl can use this handler too. [offtopic] Regarding my implementation, that was first only internal service which i published later.[/offtopic] |
Most handlers use curl or raw sockets yes. I think that's fine to be honest, it's the first time anyone even asks about it in all these years. I wouldn't add a dependency on guzzle just for that. |
@Seldaek it is not mine case (i have curl everywhere), but I know some hostings, that have curl disabled. Thats why I have But I agree curl is very common nowdays. @hkdobrev what about support for non-emoji icons? ( |
$attachment['fields'][] = array( | ||
'title' => "Extra", | ||
'value' => $this->stringify($record['extra']), | ||
'short' => $this->useShortAttachment, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could be true
here, as we know the value. It may be more readable
$attachment['fields'][] = array( | ||
'title' => $var, | ||
'value' => $val, | ||
'short' => $this->useShortAttachment, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could be false
directly
if (!extension_loaded('openssl')) { | ||
throw new MissingExtensionException('The OpenSSL PHP extension is required to use the SlackHandler'); | ||
throw new MissingExtensionException( | ||
'The OpenSSL PHP extension is required to use the SlackHandler' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this change should be reverted
$level = Logger::CRITICAL, | ||
$bubble = true, | ||
$useShortAttachment = false, | ||
$includeContextAndExtra = false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Monolog always has the signature on one line
private $channel; | ||
|
||
/** | ||
* @param string $token Slackbot token |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing phpdoc for $slackTeam
|
||
/** | ||
* @param string $webhookUrl Slack Webhook URL | ||
* @param string $channel Slack channel (encoded ID or name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
string|null
} | ||
} | ||
|
||
$dataArray['attachments'] = json_encode(array($attachment)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if I use it the right way, but now I've got:
{"username":"TestBot","text":"","attachments":"[{\\"fallback\\":\\"Testing Slackhandler!\\",\\"color\\":\\"good\\",\\"fields\\":[{\\"title\\":\\"Level\\",\\"value\\":\\"INFO\\",\\"short\\":true}],\\"title\\":\\"Message\\",\\"text\\":\\"Testing Slackhandler!\\"}]","channel":"development-logging"}
Changing this line to:
$dataArray['attachments'] = [$attachment];
Output:
{"username":"TestBot","text":"","attachments":[{"fallback":"Testing Slackhandler!","color":"good","fields":[{"title":"Level","value":"INFO","short":true}],"title":"Message","text":"Testing Slackhandler!"}],"channel":"development-logging"}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@martijncalker Thanks for your feedback! This is now fixed thanks to the work of @an1zhegorodov
@hkdobrev any update here? Should I wait a couple days to get a chance to include this in the next 1.x release or will you need more time to finalize it? No stress I just need to know :) |
@an1zhegorodov Thank you for your work! Could you please confirm that your changes didn't incur any backwards incompatible changes? Not just to the PHP API, but also to the way the pre-existing |
'value' => $record['level_name'], | ||
'short' => true, | ||
); | ||
$attachment['fields'][] = $this->generateAttachmentField('Level', $record['level_name'], true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@an1zhegorodov I think here in the else
of if ($this->useShortAttachment)
we should really pass false
for the short attachment option instead of true
, don't you think? Just like @stof's comment: #846 (comment)
@stof While I agree with your comment and would have changed it without thinking twice, this is an example where not using the property introduces a bug more easily.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm sorry for commenting on an outdated diff, will copy my comment on the updated line as it is still valid and so the comment could be visible.
$attachment['title'] = $record['level_name']; | ||
} else { | ||
$attachment['title'] = 'Message'; | ||
$attachment['fields'][] = $this->generateAttachmentField('Level', $record['level_name'], true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@an1zhegorodov I think here in the else
of if ($this->useShortAttachment)
we should really pass false
for the short attachment option instead of true
, don't you think? Just like @stof's comment: #846 (comment)
@stof While I agree with your comment and would have changed it without thinking twice, this is an example where not using the property introduces a bug more easily.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@an1zhegorodov Thanks for pointing this out! I got confused from the if-else and for being away from this for a while.
This is a good suggestion. However, I wanted to limit the scope of this PR to provide the current functionality, but through the Slackbot or Webhooks without going through the Slack API. I think it should be extended to support everything Slack supports. But this could be done in a later Monolog release, ideally in 2.x when it could be refactored with breaking the public interface of the handler and its configuration so it could have a more flexible way to support everything Slack offers and even future features of Slack webhooks without changing the API and addition additional arguments to methods. What do you think? Do you think this should be done as part of this PR? Cheers! |
I've marked a couple of methods as deprecated now. However, I disagree with marking the whole handler as deprecated as people who already use the Slack API could have a valid case and could continue to use it. Using the Slack API is not deprecated, so I don't see why we should deprecated the handler. Although, 2.x would be a good place to refactor the public interface and allow for more flexibility so the interface doesn't depend on every property Slack supports, I don't see why to deprecate the whole method of logging to the Slack API. What do you think? Are you still considering removing the whole handler in 2.x? |
Please let me know if you'd like commits squashed or partially squashed. Thanks to all for all the feedback and help! I'm sorry for delaying it! |
@hkdobrev I didn't change public API, only made |
} | ||
} | ||
|
||
$dataArray['attachments'] = array($attachment); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed json_encode
here. I think this will break SlackHandler
, despite working fine with SlackWebhookHandler
. SlackHandler
sends data with application/x-www-form-urlencoded
headers, and it looks like slack expects attachments
field to be json_encoded in that case.
A few optoins I figured:
- json_encode
attachments
inSlackHandler
- change content-type to
application/json
and json_encode the whole record inSlackHandler
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@an1zhegorodov Could you elaborate more on the second option? Would that work with the Slack API?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hkdobrev That should work according to Slack API documentation
invalid_post_type
The method was called via a POST request, but the specified Content-Type was invalid. Valid types are: application/json application/x-www-form-urlencoded multipart/form-data text/plain.
Using json will also make SlackHandler
tests more clean and simple. No regex required.
I'll work on this tonight and test it out. Sorry for missing that in the first place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was wrong. Slack API docs are confusing, they actually don't support json.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@an1zhegorodov That may be an outdated answer, though.
- It's from 2015 (There's a comment from this month saying it doesn't support it 😞 )
- The Slack API documentation you have linked earlier says JSON is supported.
- Slack API website now has a message builder tool and it uses JSON exclusively. See an example.
Have you tried it out on the API? I might be able to try it out tomorrow if you won't be able to.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- It's still true, I tested it via Postman and I have the same error message they had in 2015
- It says that application/json is a valid value for Content-Type header. Well, it doesn't complain about that header value indeed 😆
- The comment you mentioned says exactly that. I think they use JSON there just for the sake of editing simplicity, it's not processed by an API, but by custom controller.
Never mind. Finishing it.
* @param int $level The minimum logging level at which this handler will be triggered | ||
* @param bool $bubble Whether the messages that are handled can bubble up the stack or not | ||
*/ | ||
public function __construct( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hkdobrev Are we going to one-line arguments for consistency?
Also, we can make the order of arguments the same as in SlackHandler
(except here we'll have webhookUrl
instead of token
). This makes switching between SlackHandler
and SlackWebhookHandler
much easier.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@an1zhegorodov Yes, I'd change __construct()
to be on a single line everywhere as per @stof's comment. I was going more for PSR-2 conventions.
However, I wouldn't want to unify argument order as it used to be in SlackHandler
. See #197. I think the order in SlackHandler
is the old order which would be changed in 2.0. So it would be easier to switch to 2.0 if you use the new Slack handlers, the old one is like that anyway so if you SlackHandler
you'd need to change it for 2.0 anyway.
So anyone is welcome to suggest a more suitable order of arguments for SlackWebhookHandler
and SlackbotHandler
to adhere more to 2.0 styleguide, but I wouldn't want to make them like SlackHandler
.
E_USER_DEPRECATED | ||
); | ||
|
||
return $this->slackRecord->getAttachmentColor($level); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a thought. What if someone extended SlackHanlder
just to make colors mapping different? He'll get default colors mapping after update, right? Looks like we're breaking backwards compatibility here. Same happens with stringify
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. We would be breaking extensions which adhere to the Liskov principle, because we are not calling this method anymore. The deprecation notice would help, but not to people not familiar with Monolog. However, this is only about people extending SlackHandler
as we are not changing anything for people using the public API. This is only the protected
API. So I think we could close our eyes for that BC change here, because we have a deprecation notice for people who extended it.
@Seldaek Do you think it's OK breaking the use of classes extended SlackHandler
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I think I can live with a minor break there.
Note that the 2.0 constructor arguments are still very likely to change
so don't attach too much importance to that.. Make it work for 1.x and
we'll see.
|
I haven't looked into the code yet, but I have a question. I'm currently using this SlackWebhookHandler. The one thing which is missing is the good formatter for The formatter that would pretty print the array would be preferred. Back when my colleagues and I used our own logger, we used to turn on the markdown option ( Any solutions to this problem here? |
Conflicts: - tests/Monolog/Handler/Slack/SlackRecordTest.php - merged the tests
Slack API requires to json_encode the attachment field.
This is for consistency with the rest of the handlers.
@an1zhegorodov Stringify is indeed some improvement, but with multidimensional arrays it's still pretty much useless. One way I've seen this solved is either:
|
@mirfilip Once this is merged, I'll come up with a separate PR addressing this and a few other issues. Would appreciate your feedback. |
@mirfilip @an1zhegorodov I also think it's better a new issue to be opened for this and tackled separately from the majority of the Slack handlers work. |
Hey guys, Thanks for this amazing work, can we see it merged soon @Seldaek ? |
Thanks everyone :) |
1.22 is out.. |
- [x] Exclude `extra`/`context`, `datetime`, `level` from message when attachment is used - [x] Use `ts` attachment key to display `datetime` considering user timezone - [x] [Support](#846 (comment)) custom user images - [x] [Allow](#894 (comment)) to setup username from slack - [x] [Improve](#846 (comment)) array formatting within `context`/`extra` - [x] [Support](#745) `include_stacktraces` option when attachment is not used and always include stacktraces when attachment is used - [x] Support `extra`/`context` field exclusion - [x] Update tests
May I ask why cURL was preferred over Socket? Is it possible you could to move to socket instead of cURL? |
The I'm not sure if these handlers could use a socket. cURL is simpler and based on their examples in the docs. I think only the streaming API would require a socket. Why do you need to use a socket? If you use webhooks or the Slackbot, their examples give you just a webhook URL. |
I hope I am not saying something incredibly stupid but I think using Sockets you can fire and forget an HTTP request from PHP. https://stackoverflow.com/a/14668762/4158811 The reason is that I don't want my application to break/stay halt if my Slack service is down. I can see also that with the current implementation of SlackWebhook it retries the cURL request five times and I don't see a timeout setting so most probably my app will stay frozen while trying to call the webhook. Not sure though if SocketHandler of monolog is also waiting for the response or it has a "fire and forget" logic. |
"Fire and forget" would only work if there's no need to write data to the socket. We need to do that, so it would be locking operation with either Sockets or cURL. If performance is critical, I'd also consider using |
See #743 (comment)
This is keeping the previous
SlackHandler
, but extracts the message formatting logic and introduces two new Slack handlers:SlackbotHandler
- this is the simplest way to log to Slack and most people could use that. It doesn't allow fancy formatting, but has autolinking and the simplest configuration with two clicks in the Slack settings and getting a token.SlackWebhookHandler
- This is a bit more advanced as it allows for the same formatting and adding attachements as theSlackHandler
, but it uses the Slack Webhooks which are quite easier to set up than the OAuth API. The minimum it requires is a webhook URL which is a retrievable with about two clicks in the Slack settings. Even the channel is optional as it could be configured in the integration.This is probably not the leanest way to implement what we've discussed in #743, but after working at this I believe this is the simplest and the right approach.
While we could implement everything in one handler the API would become horrible and it would be harder to understand from users. Providing choice with simple to use separate classes is better IMHO. Apart from this the
SlackHandler
extends theSocketHandler
and the webhooks and the Slackbot wouldn't work nicely with that.What do you think?
@Seldaek @gkedzierski @Gummibeer @nisbeti
SlackRecord
SlackbotHandler
SlackWebhookHandler
SlackHandler
using the newSlackRecord
SlackRecord
SlackbotHandler
SlackWebhookHandler
SlackHandler