-
Notifications
You must be signed in to change notification settings - Fork 0
Feature: Sending endpoint request data to a Microsoft Teams channel #21
Comments
To expand on my earlier notes:
For a local (localhost) app instance, concurrency might not have a large impact, but if run centrally I'm not sure how else this could be reliably handled. This would likely come as a later, separate feature/enhancement,, but having the user be able to specify:
would allow for creating unique pairs so that you could have multiple groups or individual developers share an instance of this app for testing purposes with each group receiving messages on a separate Teams channel. |
Current focus. Once this is implemented here it will help me implement elsewhere where it is a major feature/blocker for development. |
To effectively pass relevant details to a Teams channel, I feel like we'll have to extend the I first created a truncated/modified JSON payload based on the "Trello - Card created" example JSON from https://messagecardplayground.azurewebsites.net/. {
"summary": "Summary text here",
"title": "Title goes here",
"text": "Title text goes here",
"themeColor": "#3479BF",
"sections": [
{
"title": "first section",
"text": "first section text here",
"markdown": true
},
{
"title": "Details",
"text": null,
"markdown": true,
"facts": [
{
"name": "Labels",
"value": "Designs, redlines"
},
{
"name": "Due date",
"value": "Dec 7, 2016"
}
]
}
],
"entities": null,
"potentialAction": [
{
"target": [
"http://example.com/report/view/12345"
],
"@context": "http://schema.org",
"@type": "ViewAction",
"@id": null,
"name": "View report",
"isPrimaryAction": false
}
],
"replyTo": null,
"threadingCriteria": null
}
I then used https://mholt.github.io/json-to-go/ to produce this Go struct: type MessageCardExtended struct {
Summary string `json:"summary,omitempty"`
Title string `json:"title"`
Text string `json:"text"`
ThemeColor string `json:"themeColor"`
Sections []struct {
Title string `json:"title"`
Text string `json:"text"`
Markdown bool `json:"markdown"`
Facts []struct {
Name string `json:"name"`
Value string `json:"value"`
} `json:"facts,omitempty"`
} `json:"sections,omitempty"`
Entities interface{} `json:"entities,omitempty"`
PotentialAction []struct {
Target []string `json:"target"`
Context string `json:"@context"`
Type string `json:"@type"`
ID interface{} `json:"@id"`
Name string `json:"name"`
IsPrimaryAction bool `json:"isPrimaryAction"`
} `json:"potentialAction,omitempty"`
ReplyTo interface{} `json:"replyTo,omitempty"`
ThreadingCriteria interface{} `json:"threadingCriteria,omitempty"`
} I dropped in some additional |
I say that, but some of the fields don't appear to be listed on the official reference doc: Examples:
I've removed them from the sample I'm working from. |
In particular: - Multiple sections - Facts (subfield for Sections) - PotentialAction - could be used to link back to reports or more details not provided by a Teams notification refs atc0005/bounce#21
Found it: https://connectplayground.azurewebsites.net/ I pulled the example from that site. |
Current sample JSON: {
"@type": "MessageCard",
"@context": "http://schema.org/extensions",
"summary": "Summary text here",
"title": "Client submission received",
"text": "`GET` request received on `/api/v1/echo/json` endpoint",
"themeColor": "#3479BF",
"sections": [
{
"title": "Received JSON payload",
"text": "```{\"title\":\"testing\"}```",
"markdown": true
},
{
"title": "Individual Go struct fields here",
"text": null,
"markdown": true,
"facts": [
{
"name": "Client IP Address",
"value": "1.2.3.4"
},
{
"name": "Endpoint used",
"value": "/api/v1/echo/json"
}
]
}
],
"potentialAction": [
{
"target": [
"http://web.example.local:8000/app/search/@go?sid=scheduler_admin_search_W2_at_14232356_132"
],
"@context": "http://schema.org",
"@type": "ViewAction",
"@id": null,
"name": "View full Splunk report",
"isPrimaryAction": true
}
]
} Still refining it. For example, I don't know whether |
Context: Microsoft Teams supports Markdown code formatting via using pairs of ` or ``` characters to wrap code blocks. |
In particular: - Multiple sections - Facts (subfield for Sections) - PotentialAction - could be used to link back to reports or more details not provided by a Teams notification refs atc0005/bounce#21
Question to self: Should a failure to submit messages to Microsoft Teams result in a HTTP Status Code change? In other words, if what the client sent was fine and the data was displayed via console output without issue, should we ...
|
For now I'll refrain from reporting the error sending to Teams via HTTP Status Code changes since sending to Teams is a supplementary action and not currently considered a requirement for this app. I'll need to give this further thought to see if there is a standard practice around this. |
Quick note: Performance with the way the current codebases are setup is pretty sluggish. Not 100% sure whether it's all of the debug logging or just the delay in getting a message to Teams and coming back with a response. Current non-concurrent function: func sendMessage(webhookURL string, msgCard goteamsnotify.MessageCard) error {
if webhookURL == "" {
log.Debug("webhookURL not defined, skipping message submission to Microsoft Teams channel")
}
// Submit message card
if err := send2teams.SendMessage(webhookURL, msgCard); err != nil {
errMsg := fmt.Errorf("ERROR: Failed to submit message to Microsoft Teams: %v", err)
log.Error(errMsg.Error())
return errMsg
}
// Emit basic success message
log.Info("Message successfully sent to Microsoft Teams")
return nil
} Concurrent, fast yet with a bug version: func sendMessage(webhookURL string, msgCard goteamsnotify.MessageCard) error {
if webhookURL == "" {
log.Debug("webhookURL not defined, skipping message submission to Microsoft Teams channel")
}
// NOTE: Unscientific testing showed a MASSIVE difference in
// response times when launching this in a goroutine. We'll
// need to find a way to communicate *back* to the caller
// the results of the goroutine, otherwise we are not
// able to properly handle errors.
go func() error {
// Submit message card
if err := send2teams.SendMessage(webhookURL, msgCard); err != nil {
errMsg := fmt.Errorf("ERROR: Failed to submit message to Microsoft Teams: %v", err)
log.Error(errMsg.Error())
return errMsg
}
// Emit basic success message
log.Info("Message successfully sent to Microsoft Teams")
return nil
}()
} I've not worked with them enough to implement properly, but I would need some reliable way to communicate back the error state to the caller. |
https://blog.simon-frey.eu/manual-flush-golang-http-responsewriter/
and:
The workarounds are to reduce the buffer size (not recommended) or manually flushing the if f, ok := rw.(http.Flusher); ok {
f.Flush()
} Here is their updated implementation: func h(rw http.ResponseWriter, req *http.Request) {
io.Copy(rw, loadingHTMLByteReader)
if f, ok := rw.(http.Flusher); ok {
f.Flush()
}
tResult = performLongRunningTask()
rw.Write(tResult)
} |
Example before flushing the Example after flushing the Browsing the endpoints via web browser still "feels" a little sluggish, but much, much faster than before. I implemented the buffer flush like so: writeTemplate := func() {
err := tmpl.Execute(mw, ourResponse)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
log.Errorf("error occurred while trying to execute template: %v", err)
// We force a a return here since it is unlikely that we should
// execute any other code after failing to generate/write out our
// template
return
}
// Manually flush http.ResponseWriter
// https://blog.simon-frey.eu/manual-flush-golang-http-responsewriter/
if f, ok := w.(http.Flusher); ok {
log.Debug("Manually flushing http.ResponseWriter")
f.Flush()
} else {
log.Warn("http.Flusher interface not available, cannot flush http.ResponseWriter")
log.Warn("Not flushing http.ResponseWriter may cause a noticeable delay between requests")
}
} The log statements ( This function is called from multiple places throughout the echo handler, so adding the flush here where our output template is executed seemed to make the most sense (especially since it is called just before we try sending a message via Teams). |
Worth noting: The My suspicion is that the 405 return code provided by the |
Current status of work for this issueAt this point I believe the Next steps for this issueAs I write this, the After this issue is resolvedOnce the PR for this issue lands I'll go ahead and implement basic SMTP notifications support over unauthenticated 25/tcp (via #19) with the assumption that the primary use case will be sending to internal mail gateways or dev VMs/containers where encryption or tight security isn't required. A follow-up PR could (and probably will) add the additional function to allow sending outside of an isolated network to Gmail, Yahoo, etc, or even to a local corporate mail server where encryption is supported, encouraged or required. |
ADDED - Add support for Microsoft Teams notifications - configurable retry, retry delay settings - rate-limited submissions to help prevent unintentional abuse of remote API - currently hard-coded, but will likely expose this as a flag in a future release - Add monitoring/reporting of notification channels with pending items - Add monitoring/reporting of notification statistics - total - pending - success - failure - Capture `Ctrl+C` and attempt graceful shutdown - Plumbed `context` throughout majority of application for cancellation and timeout functionality - still learning proper use of this package, so likely many mistakes that will need to be fixed in a future release - Logging - add *many* more debug statements to help with troubleshooting CHANGED - Dependencies - Use `atc0005/go-teams-notify` package - fork of original package with current features and some additional changes not yet accepted upstream - Use `atc0005/send2teams` package - provides wrapper for upstream functionality with message retry, delayfunctionality - provides formatting helper functions - provides additional webhook URL validation - Drop indirect dependency - Update `golang/gddo` - Add commented entries to have Go use local copies of packages for fast prototyping work FIXED - GoDoc formatting - remove forced line-wrap which resulted in unintentional code block formatting of non-code content - Refactor logging, flag handling - not user visible, so not recording as a "change" - Manually flush `http.ResponseWriter` to (massively) speed up response time for client requests - Move template parsing to `main()` in an effort to speed up endpoint response time for client requests REFERENCES - refs #19 - partial work; stubbed out - refs #21 - refs #26 - refs #27 - refs #28
ADDED - Add support for Microsoft Teams notifications - configurable retry, retry delay settings - rate-limited submissions to help prevent unintentional abuse of remote API - currently hard-coded, but will likely expose this as a flag in a future release - Add monitoring/reporting of notification channels with pending items - Add monitoring/reporting of notification statistics - total - pending - success - failure - Capture `Ctrl+C` and attempt graceful shutdown - Plumbed `context` throughout majority of application for cancellation and timeout functionality - still learning proper use of this package, so likely many mistakes that will need to be fixed in a future release - Logging - add *many* more debug statements to help with troubleshooting CHANGED - Dependencies - Use `atc0005/go-teams-notify` package - fork of original package with current features and some additional changes not yet accepted upstream - Use `atc0005/send2teams` package - provides wrapper for upstream functionality with message retry, delayfunctionality - provides formatting helper functions - provides additional webhook URL validation - Drop indirect dependency - Update `golang/gddo` - Add commented entries to have Go use local copies of packages for fast prototyping work FIXED - GoDoc formatting - remove forced line-wrap which resulted in unintentional code block formatting of non-code content - Refactor logging, flag handling - not user visible, so not recording as a "change" - Manually flush `http.ResponseWriter` to (massively) speed up response time for client requests - Move template parsing to `main()` in an effort to speed up endpoint response time for client requests REFERENCES - refs #19 - partial work; stubbed out - refs #21 - refs #26 - refs #27 - refs #28
ADDED - Add support for Microsoft Teams notifications - configurable retry, retry delay settings - rate-limited submissions to help prevent unintentional abuse of remote API - currently hard-coded, but will likely expose this as a flag in a future release - Add monitoring/reporting of notification channels with pending items - Add monitoring/reporting of notification statistics - total - pending - success - failure - Capture `Ctrl+C` and attempt graceful shutdown - Plumbed `context` throughout majority of application for cancellation and timeout functionality - still learning proper use of this package, so likely many mistakes that will need to be fixed in a future release - Logging - add *many* more debug statements to help with troubleshooting - Documentation - GoDoc coverage for new features - README update to give example of Teams coverage CHANGED - Dependencies - Use `atc0005/go-teams-notify` package - fork of original package with current features and some additional changes not yet accepted upstream - Use `atc0005/send2teams` package - provides wrapper for upstream functionality with message retry, delayfunctionality - provides formatting helper functions - provides additional webhook URL validation - Drop indirect dependency - Update `golang/gddo` - Add commented entries to have Go use local copies of packages for fast prototyping work FIXED - GoDoc formatting - remove forced line-wrap which resulted in unintentional code block formatting of non-code content - Refactor logging, flag handling - not user visible, so not recording as a "change" - Manually flush `http.ResponseWriter` to (massively) speed up response time for client requests - Move template parsing to `main()` in an effort to speed up endpoint response time for client requests REFERENCES - refs #19 - partial work; stubbed out - refs #21 - refs #26 - refs #27 - refs #28 WIP: Update README example, add example teams submission screenshot
The initial implementation could send each endpoint request over to a specified Microsoft Teams channel, but a later refinement might improve on this by batching the requests for bulk submission, either immediately when hitting a specified queue threshold or at a schedule frequency (if any are in the queue).
The existing
atc0005/send2teams
project code could serve as a starting point for adding this feature.The text was updated successfully, but these errors were encountered: