1
0
mirror of https://github.com/nikoksr/notify.git synced 2024-11-21 16:46:32 +02:00

feat(service): add syslog (#211)

This commit is contained in:
Niko Köser 2022-02-13 18:18:03 +01:00 committed by GitHub
parent 2615041103
commit 5550aedb73
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 275 additions and 48 deletions

View File

@ -27,6 +27,8 @@ Any misuse of this library is your own liability and responsibility and cannot b
Spamming through the use of this library **may get you permanently banned** on most supported platforms.
Since Notify is highly dependent on the consistency of the supported external services and the corresponding latest client libraries, we cannot guarantee its reliability nor its consistency, and therefore you should probably not use or rely on Notify in critical scenarios.
## Install <a id="install"></a>
```sh
@ -58,60 +60,38 @@ _ = notify.Send(
## Supported services <a id="supported_services"></a>
> Please create feature requests for missing services (see #3 for example)
> Please create feature requests for missing services (see [#3](https://github.com/nikoksr/notify/issues/3) for example)
- *Amazon SES*
- *Amazon SNS*
- *DingTalk*
- *Discord*
- *Email*
- *Line & Line Notify*
- *Mailgun*
- *Microsoft Teams*
- *Plivo*
- *Pushbullet*
- *RocketChat*
- *SendGrid*
- *Slack*
- *Telegram*
- *TextMagic*
- *Twitter*
- *WeChat*
- *WhatsApp*
| Service | Path | Credits |
|--------------------------------------------------------------|------------------------------------------|-------------------------------------------------------------------------------------------------|
| [Amazon SES](https://aws.amazon.com/ses) | [service/amazonses](service/amazonses) | [aws/aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2) |
| [Amazon SNS](https://aws.amazon.com/sns) | [service/amazonsns](service/amazonsns) | [aws/aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2) |
| [DingTalk](https://www.dingtalk.com) | [service/dinding](service/dingding) | [blinkbean/dingtalk](https://github.com/blinkbean/dingtalk) |
| [Discord](https://discord.com) | [service/discord](service/discord) | [bwmarrin/discordgo](https://github.com/bwmarrin/discordgo) |
| [Email](https://wikipedia.org/wiki/Email) | [service/mail](service/mail) | [jordan-wright/email](https://github.com/jordan-wright/email) |
| [Line](https://line.me) | [service/line](service/line) | [line/line-bot-sdk-go](https://github.com/line/line-bot-sdk-go) |
| [Line Notify](https://notify-bot.line.me) | [service/line](service/line) | [utahta/go-linenotify](https://github.com/utahta/go-linenotify) |
| [Mailgun](https://www.mailgun.com) | [service/mailgun](service/mailgun) | [mailgun/mailgun-go](https://github.com/mailgun/mailgun-go) |
| [Microsoft Teams](https://www.microsoft.com/microsoft-teams) | [service/msteams](service/msteams) | [atc0005/go-teams-notify](https://github.com/atc0005/go-teams-notify) |
| [Plivo](https://www.plivo.com) | [service/plivo](service/plivo) | [plivo/plivo-go](https://github.com/plivo/plivo-go) |
| [Pushbullet](https://www.pushbullet.com) | [service/pushbullet](service/pushbullet) | [cschomburg/go-pushbullet](https://github.com/cschomburg/go-pushbullet) |
| [RocketChat](https://rocket.chat) | [service/rocketchat](service/rocketchat) | [RocketChat/Rocket.Chat.Go.SDK](https://github.com/RocketChat/Rocket.Chat.Go.SDK) |
| [SendGrid](https://sendgrid.com) | [service/sendgrid](service/sendgrid) | [sendgrid/sendgrid-go](https://github.com/sendgrid/sendgrid-go) |
| [Slack](https://slack.com) | [service/slack](service/slack) | [slack-go/slack](https://github.com/slack-go/slack) |
| [Syslog](https://wikipedia.org/wiki/Syslog) | [service/syslog](service/syslog) | [log/syslog](https://pkg.go.dev/log/syslog) |
| [Telegram](https://telegram.org) | [service/telegram](service/telegram) | [go-telegram-bot-api/telegram-bot-api](https://github.com/go-telegram-bot-api/telegram-bot-api) |
| [TextMagic](https://www.textmagic.com) | [service/textmagic](service/textmagic) | [textmagic/textmagic-rest-go-v2](https://github.com/textmagic/textmagic-rest-go-v2) |
| [Twitter](https://twitter.com) | [service/twitter](service/twitter) | [dghubble/go-twitter](https://github.com/dghubble/go-twitter) |
| [WeChat](https://www.wechat.com) | [service/wechat](service/wechat) | [silenceper/wechat](https://github.com/silenceper/wechat) |
| [WhatsApp](https://www.whatsapp.com) | [service/whatsapp](service/whatsapp) | [Rhymen/go-whatsapp](https://github.com/Rhymen/go-whatsapp) |
## Credits <a id="credits"></a>
## Logo <a id="logo"></a>
- Amazon SES support: [aws/aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2)
- Amazon SNS support: [aws/aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2)
- DingTalk support: [blinkbean/dingtalk](https://github.com/blinkbean/dingtalk)
- Discord support: [bwmarrin/discordgo](https://github.com/bwmarrin/discordgo)
- Email support: [jordan-wright/email](https://github.com/jordan-wright/email)
- Line support: [line/line-bot-sdk-go](https://github.com/line/line-bot-sdk-go)
- Line Notify support: [utahta/go-linenotify](https://github.com/utahta/go-linenotify)
- Logo: [MariaLetta/free-gophers-pack](https://github.com/MariaLetta/free-gophers-pack)
- Mailgun support: [mailgun/mailgun-go](https://github.com/mailgun/mailgun-go)
- Microsoft Teams support: [atc0005/go-teams-notify](https://github.com/atc0005/go-teams-notify)
- Plivo support: [plivo/plivo-go](https://github.com/plivo/plivo-go)
- Pushbullet support: [cschomburg/go-pushbullet](https://github.com/cschomburg/go-pushbullet)
- RocketChat Support: [RocketChat/Rocket.Chat.Go.SDK](https://github.com/RocketChat/Rocket.Chat.Go.SDK)
- SendGrid support: [sendgrid/sendgrid-go](https://github.com/sendgrid/sendgrid-go)
- Slack support: [slack-go/slack](https://github.com/slack-go/slack)
- Telegram support: [go-telegram-bot-api/telegram-bot-api](https://github.com/go-telegram-bot-api/telegram-bot-api)
- TextMagic support: [textmagic/textmagic-rest-go-v2](https://github.com/textmagic/textmagic-rest-go-v2)
- Twitter: [dghubble/go-twitter](https://github.com/dghubble/go-twitter)
- WeChat: [silenceper/wechat](https://github.com/silenceper/wechat)
- WhatsApp: [Rhymen/go-whatsapp](https://github.com/Rhymen/go-whatsapp)
## Author <a id="author"></a>
**Niko Köser**
* Twitter: [@nikoksr](https://twitter.com/nikoksr)
* Github: [@nikoksr](https://github.com/nikoksr)
The [logo](https://github.com/MariaLetta/free-gophers-pack) was made by the amazing [MariaLetta](https://github.com/MariaLetta).
## Contributing <a id="contributing"></a>
Contributions, issues and feature requests are welcome!<br />Feel free to check [issues page](https://github.com/nikoksr/notify/issues). You can also take a look at the [contributing guide](https://github.com/nikoksr/notify/blob/main/CONTRIBUTING.md).
Contributions, issues and feature requests are very welcome! Feel free to check [issues page](https://github.com/nikoksr/notify/issues). Please also take a look at the [contribution guidelines](https://github.com/nikoksr/notify/blob/main/CONTRIBUTING.md).
## Show your support <a id="support"></a>

9
SECURITY.md Normal file
View File

@ -0,0 +1,9 @@
# Security Policy
## Supported Versions
Only the last stable version at any given point.
## Reporting a Vulnerability
Vulnerabilities can be disclosed via email to contact@nikoksr.dev.

31
service/syslog/doc.go Normal file
View File

@ -0,0 +1,31 @@
/*
Package syslog provides message notification integration for local or remote syslogs.
Usage:
package main
import (
"context"
"log"
sl "log/syslog"
"github.com/nikoksr/notify"
"github.com/nikoksr/notify/service/syslog"
)
func main() {
syslogSvc, err := syslog.New(sl.LOG_USER, "")
if err != nil {
log.Fatalf("syslog.New() failed: %v", err)
}
notify.UseServices(syslogSvc)
err = notify.Send(context.Background(), "TEST", "Hello, World!")
if err != nil {
log.Fatalf("notify.Send() failed: %v", err)
}
}
*/
package syslog

View File

@ -0,0 +1,45 @@
// Code generated by mockery 2.10.0. DO NOT EDIT.
package syslog
import mock "github.com/stretchr/testify/mock"
// mockSyslogWriter is an autogenerated mock type for the mockSyslogWriter type
type mockSyslogWriter struct {
mock.Mock
}
// Close provides a mock function with given fields:
func (_m *mockSyslogWriter) Close() error {
ret := _m.Called()
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
} else {
r0 = ret.Error(0)
}
return r0
}
// Write provides a mock function with given fields: p
func (_m *mockSyslogWriter) Write(p []byte) (int, error) {
ret := _m.Called(p)
var r0 int
if rf, ok := ret.Get(0).(func([]byte) int); ok {
r0 = rf(p)
} else {
r0 = ret.Get(0).(int)
}
var r1 error
if rf, ok := ret.Get(1).(func([]byte) error); ok {
r1 = rf(p)
} else {
r1 = ret.Error(1)
}
return r0, r1
}

73
service/syslog/syslog.go Normal file
View File

@ -0,0 +1,73 @@
package syslog
import (
"context"
"io"
"log/syslog"
"strings"
"github.com/pkg/errors"
)
// mockSyslogWriter abstracts log/syslog for writing unit tests.
type syslogWriter interface {
io.WriteCloser
}
// Service encapsulates a syslog daemon writer.
type Service struct {
writer syslogWriter
}
// dial is a wrapper function around syslog.Dial. It normalizes the prefix tag in case that it's empty and returns
// a new Service with the writer field set to writer from the call to syslog.Dial.
func dial(network, raddr string, priority syslog.Priority, tag string) (*Service, error) {
if strings.TrimSpace(tag) == "" {
tag = "notify"
}
// Usually we could call syslog.New and syslog.Dial respectively for specific use-cases. But since syslog.New is
// only a wrapper around a call to syslog.Dial without information about the network we're doing the same here to
// keep the API a little more clean.
writer, err := syslog.Dial(network, raddr, priority, tag)
if err != nil {
return nil, err
}
return &Service{writer: writer}, nil
}
// New returns a new instance of a Service notification service. Parameter 'tag' is used as a log prefix and may be left
// empty, it has a fallback value.
func New(priority syslog.Priority, tag string) (*Service, error) {
return dial("", "", priority, tag)
}
// NewFromDial returns a new instance of a Service notification service. The underlying syslog writer establishes a
// connection to a log daemon by connecting to address raddr on the specified network. Parameter 'tag' is used as a log
// prefix and may be left empty, it has a fallback value.
// Calling NewFromDial with network and raddr being empty strings is equal in function to calling New directly.
func NewFromDial(network, raddr string, priority syslog.Priority, tag string) (*Service, error) {
return dial(network, raddr, priority, tag)
}
// Close the underlying syslog writer.
func (s *Service) Close() error {
return s.writer.Close()
}
// Send takes a message subject and a message body and sends them to all previously set channels.
// user used for sending the message has to be a member of the channel.
func (s *Service) Send(ctx context.Context, subject, message string) error {
select {
case <-ctx.Done():
return ctx.Err()
default:
_, err := s.writer.Write([]byte(subject + ": " + message))
if err != nil {
return errors.Wrap(err, "failed to write message to syslog")
}
}
return nil
}

View File

@ -0,0 +1,89 @@
package syslog
import (
"context"
"log/syslog"
"testing"
"github.com/pkg/errors"
"github.com/stretchr/testify/require"
)
func TestNew(t *testing.T) {
assert := require.New(t)
// Test creating a local writer with invalid log priority.
svc, err := New(-1, "")
assert.Error(err)
assert.Nil(svc)
// Test creating a local writer successfully.
svc, err = New(syslog.LOG_USER, "")
assert.NoError(err)
assert.NotNil(svc)
err = svc.Close()
assert.NoError(err)
// Test creating a remote writer with invalid port.
svc, err = NewFromDial("tcp", "localhost:99999", syslog.LOG_USER, "")
assert.Error(err)
assert.Nil(svc)
// Test creating a remote writer successfully.
svc, err = NewFromDial("", "", syslog.LOG_USER, "")
assert.NoError(err)
assert.NotNil(svc)
err = svc.Close()
assert.NoError(err)
}
func TestSend(t *testing.T) {
assert := require.New(t)
ctx := context.Background()
svc := new(Service)
// Test syslog writer returning error
mockClient := new(mockSyslogWriter)
mockClient.
On("Write", []byte("test: message")).
Return(0, errors.New("some error"))
svc.writer = mockClient
err := svc.Send(ctx, "test", "message")
assert.Error(err)
mockClient.AssertExpectations(t)
// Test syslog writer returning no error
mockClient = new(mockSyslogWriter)
mockClient.
On("Write", []byte("test: message")).
Return(0, nil)
svc.writer = mockClient
err = svc.Send(ctx, "test", "message")
assert.NoError(err)
mockClient.AssertExpectations(t)
// Test closing the syslog writer with error
mockClient = new(mockSyslogWriter)
mockClient.
On("Close").
Return(errors.New("some error"))
svc.writer = mockClient
err = svc.Close()
assert.Error(err)
mockClient.AssertExpectations(t)
// Test closing the syslog writer without error
mockClient = new(mockSyslogWriter)
mockClient.
On("Close").
Return(nil)
svc.writer = mockClient
err = svc.Close()
assert.NoError(err)
mockClient.AssertExpectations(t)
}