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:
parent
2615041103
commit
5550aedb73
76
README.md
76
README.md
@ -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
9
SECURITY.md
Normal 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
31
service/syslog/doc.go
Normal 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
|
45
service/syslog/mock_syslogWriter.go
Normal file
45
service/syslog/mock_syslogWriter.go
Normal 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
73
service/syslog/syslog.go
Normal 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
|
||||
}
|
89
service/syslog/syslog_test.go
Normal file
89
service/syslog/syslog_test.go
Normal 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)
|
||||
}
|
Loading…
Reference in New Issue
Block a user