narada

package module
v2.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 30, 2026 License: MIT Imports: 23 Imported by: 0

README

🖖🚀 Narada

Rapid web development, all in one place

Go Report Card GoDoc Build Status Coverage Status

What is under the hood?

Under the hood a lot of different and cool packages such as:

  • log/slog (stdlib)
  • Bun
  • Go-redis
  • Uber FX
  • Viper
  • Sentry
  • Pprof
  • Prometheus

Also it supports:

  • Workers using chapsuk workers package
  • Http.Handler binding and serving

Modules

Config

Dependency: *viper.Viper
Configuration:
Configuration file are located at NARADA_CONFIG or config.yml.
Environment BINDING_API will be replaced to binding.api.

Logger

Dependency: *slog.Logger
Configuration:

logger: 
    formatter: text # Supported values ['text', 'json']
    level: debug # Supported values ['debug', 'info', 'warn', 'error']
    catch_errors: true # Sending >=error level to sentry
    slack: false # Sending >= error level to slack 
    slack_url: "" # Slack webhook url [Required when slack is true]
    slack_icon: ""
    slack_emoji: ":ghost:"
    slack_username: "<YOUR_APP_NAME>_bot"
    slack_channel: "" #  Slack username [Required when slack is true]
Workers

This module generates

Dependency: *narada.Workers

Clients

Here all clients that are provided automatically located.

Redis

Dependency: *redis.Client Configuration:

redis:
    addr: "" # Redis address, in e.g.: 127.0.0.1:6379
    db: 0
    password: ""
    pool_size: 10
    idle_timeout: 60s
PostgreSQL

Dependency: *bun.DB
Configuration:

database:
    addr: "" # PostgreSQL address
    user: ""
    password: ""
    database: ""
    pool: 10
    ssl: true # verifies the server certificate against the system roots

Upgrading from v1

v2 is a breaking release; the module path is now github.com/cryptopay-dev/narada/v2.

  • *logrus.Logger -> *slog.Logger. Injected constructors take *slog.Logger. Replace log.WithError(err).Error("msg") with log.Error("msg", narada.Err(err)), log.WithField(k, v) with log.With(k, v), and log.Fatal(...) with narada.Fatal(log, ...) (slog has no fatal level — the record is emitted at error level and the process exits). The logrus hooks are now slog.Handler decorators: NewLogrusSentryHook/NewLogrusSlackHook became NewSentryHandler/NewSlackHandler.
  • *pg.DB -> *bun.DB. Query building moves to bun. Migrations still run on goose and the goose_db_version ledger is untouched.
  • database.ssl: true now verifies the server certificate on the migrations connection too; it previously used sslmode=verify-ca there (chain verified, hostname not) while the application connection already required a hostname match.

Documentation

Index

Constants

View Source
const ErrorKey = "error"

ErrorKey is the attribute key narada uses to carry an error on a log record. The Sentry and Slack handlers look for it to report the underlying error instead of synthesising one from the message.

Variables

This section is empty.

Functions

func Err

func Err(err error) slog.Attr

Err wraps err as a log attribute under ErrorKey. It is the slog replacement for logrus' WithError.

func Fatal

func Fatal(logger *slog.Logger, msg string, args ...any)

Fatal logs at error level and terminates the process, replacing logrus' Fatal. slog has no fatal level, so the record is emitted at slog.LevelError; Sentry is flushed first so the report survives the exit.

func NewConfig

func NewConfig(prefix string) (*viper.Viper, error)

NewConfig creates a new configuration, by default config file will be `config.yml` in same directory you run application if you want to override it you should provide `NARADA_CONFIG` environment variable.

func NewLogger

func NewLogger(config *viper.Viper) (*slog.Logger, error)

NewLogger builds the application logger from configuration.

The handler chain is Slack -> Sentry (optional) -> text/json writer, so an error record reaches both sinks and is still written to stderr.

func NewMetricsInvoke

func NewMetricsInvoke(ms *Multiserver) error

func NewNopLogger

func NewNopLogger() *slog.Logger

NewNopLogger returns a logger that discards every record.

func NewProfilerInvoke

func NewProfilerInvoke(ms *Multiserver) error

func NewSentryInvoke

func NewSentryInvoke(config *viper.Viper, lc fx.Lifecycle) error

func WithHealthcheck

func WithHealthcheck(path string) serverOption

Types

type Healthchecker

type Healthchecker func() error

type Multiserver

type Multiserver struct {
	// contains filtered or unexported fields
}

func NewMultiServers

func NewMultiServers(config *viper.Viper, logger *slog.Logger, lc fx.Lifecycle) (*Multiserver, error)

func (*Multiserver) Add

func (ms *Multiserver) Add(name string, handler http.Handler, opts ...serverOption) error

func (*Multiserver) AddHealthcheck

func (ms *Multiserver) AddHealthcheck(name, path string, check Healthchecker) error

type Narada

type Narada struct {
	// contains filtered or unexported fields
}

func New

func New(opts Options, providers ...interface{}) *Narada

func (Narada) HandleError

func (t Narada) HandleError(err error)

func (*Narada) Invoke

func (t *Narada) Invoke(fn interface{})

func (*Narada) Start

func (t *Narada) Start(fn interface{})

func (*Narada) Stop

func (t *Narada) Stop()

type Options

type Options struct {
	Name      string
	Version   string
	EnvPrefix string
}

type SentryHandler

type SentryHandler struct {
	// contains filtered or unexported fields
}

SentryHandler reports error-level records to Sentry and forwards every record to the next handler.

func NewSentryHandler

func NewSentryHandler(next slog.Handler) *SentryHandler

func (*SentryHandler) Enabled

func (h *SentryHandler) Enabled(ctx context.Context, level slog.Level) bool

func (*SentryHandler) Handle

func (h *SentryHandler) Handle(ctx context.Context, r slog.Record) error

func (*SentryHandler) WithAttrs

func (h *SentryHandler) WithAttrs(attrs []slog.Attr) slog.Handler

func (*SentryHandler) WithGroup

func (h *SentryHandler) WithGroup(name string) slog.Handler

type SlackAttachment

type SlackAttachment struct {
	Title    string        `json:"title"`
	Fallback string        `json:"fallback"`
	Text     string        `json:"text"`
	Pretext  string        `json:"pretext"`
	Color    string        `json:"color"`
	Fields   []*SlackField `json:"fields"`
}

func NewAttachment

func NewAttachment() *SlackAttachment

func (*SlackAttachment) AddField

func (a *SlackAttachment) AddField(f *SlackField)

type SlackClient

type SlackClient struct {
	Url string
	// contains filtered or unexported fields
}

func NewClient

func NewClient(url string) *SlackClient

func (*SlackClient) SendMessage

func (c *SlackClient) SendMessage(msg *SlackMessage) error

type SlackError

type SlackError struct {
	Code int
	Body string
}

func (*SlackError) Error

func (e *SlackError) Error() string

type SlackField

type SlackField struct {
	Title string `json:"title"`
	Value string `json:"value"`
	Short bool   `json:"short"`
}

func NewField

func NewField() *SlackField

type SlackHandler

type SlackHandler struct {
	// contains filtered or unexported fields
}

SlackHandler posts error-level records to a Slack webhook and forwards every record to the next handler.

func NewSlackHandler

func NewSlackHandler(config *viper.Viper, next slog.Handler) *SlackHandler

func (*SlackHandler) Enabled

func (h *SlackHandler) Enabled(ctx context.Context, level slog.Level) bool

func (*SlackHandler) Handle

func (h *SlackHandler) Handle(ctx context.Context, r slog.Record) error

func (*SlackHandler) WithAttrs

func (h *SlackHandler) WithAttrs(attrs []slog.Attr) slog.Handler

func (*SlackHandler) WithGroup

func (h *SlackHandler) WithGroup(name string) slog.Handler

type SlackMessage

type SlackMessage struct {
	Text        string             `json:"text"`
	Username    string             `json:"username"`
	IconUrl     string             `json:"icon_url"`
	IconEmoji   string             `json:"icon_emoji"`
	Channel     string             `json:"channel"`
	UnfurlLinks bool               `json:"unfurl_links"`
	Attachments []*SlackAttachment `json:"attachments"`
}

func (*SlackMessage) AddAttachment

func (m *SlackMessage) AddAttachment(a *SlackAttachment)

Directories

Path Synopsis
_examples
api_server command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL