1
0
mirror of https://github.com/mainflux/mainflux.git synced 2025-04-26 13:48:53 +08:00

NOISSUE - Implement errors package in senml transformer, readers and writers (#1108)

* Implement errors package in senml transformer, readers and writers

Signed-off-by: Ivan Milošević <iva@blokovi.com>

* Remove unused const
Return wrapped error in postgres writer

Signed-off-by: Ivan Milošević <iva@blokovi.com>

* fix default db host in postgres writer

Signed-off-by: Ivan Milošević <iva@blokovi.com>

* fix capital letters in errors messages

Signed-off-by: Ivan Milošević <iva@blokovi.com>

* use svcName instead of postgres for Promethius initialization

Signed-off-by: Ivan Milošević <iva@blokovi.com>
This commit is contained in:
Ivan Milošević 2020-04-13 12:57:53 +02:00 committed by GitHub
parent e438be4250
commit 880e193b0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 92 additions and 47 deletions

View File

@ -31,7 +31,7 @@ import (
)
const (
svcName = "postgres-writer"
svcName = "postgres-reader"
sep = ","
defLogLevel = "error"
@ -112,7 +112,7 @@ func main() {
}()
err = <-errs
logger.Error(fmt.Sprintf("Postgres writer service terminated: %s", err))
logger.Error(fmt.Sprintf("Postgres reader service terminated: %s", err))
}
func loadConfig() config {
@ -213,14 +213,14 @@ func newService(db *sqlx.DB, logger logger.Logger) readers.MessageRepository {
svc = api.MetricsMiddleware(
svc,
kitprometheus.NewCounterFrom(stdprometheus.CounterOpts{
Namespace: "postgres",
Subsystem: "message_writer",
Namespace: svcName,
Subsystem: "message_reader",
Name: "request_count",
Help: "Number of requests received.",
}, []string{"method"}),
kitprometheus.NewSummaryFrom(stdprometheus.SummaryOpts{
Namespace: "postgres",
Subsystem: "message_writer",
Namespace: svcName,
Subsystem: "message_reader",
Name: "request_latency_microseconds",
Help: "Total duration of requests in microseconds.",
}, []string{"method"}),

View File

@ -30,7 +30,7 @@ const (
defLogLevel = "error"
defNatsURL = "nats://localhost:4222"
defPort = "8180"
defDBHost = "postgres"
defDBHost = "localhost"
defDBPort = "5432"
defDBUser = "mainflux"
defDBPass = "mainflux"
@ -139,13 +139,13 @@ func newService(db *sqlx.DB, logger logger.Logger) writers.MessageRepository {
svc = api.MetricsMiddleware(
svc,
kitprometheus.NewCounterFrom(stdprometheus.CounterOpts{
Namespace: "postgres",
Namespace: svcName,
Subsystem: "message_writer",
Name: "request_count",
Help: "Number of requests received.",
}, []string{"method"}),
kitprometheus.NewSummaryFrom(stdprometheus.SummaryOpts{
Namespace: "postgres",
Namespace: svcName,
Subsystem: "message_writer",
Name: "request_latency_microseconds",
Help: "Total duration of requests in microseconds.",

View File

@ -30,3 +30,7 @@ func (res pageRes) Code() int {
func (res pageRes) Empty() bool {
return false
}
type errorRes struct {
Err string `json:"error"`
}

View File

@ -6,7 +6,6 @@ package api
import (
"context"
"encoding/json"
"errors"
"net/http"
"strconv"
"time"
@ -14,6 +13,7 @@ import (
kithttp "github.com/go-kit/kit/transport/http"
"github.com/go-zoo/bone"
"github.com/mainflux/mainflux"
"github.com/mainflux/mainflux/errors"
"github.com/mainflux/mainflux/readers"
"github.com/prometheus/client_golang/prometheus/promhttp"
"google.golang.org/grpc/codes"
@ -111,15 +111,22 @@ func encodeResponse(_ context.Context, w http.ResponseWriter, response interface
}
func encodeError(_ context.Context, err error, w http.ResponseWriter) {
switch err {
case nil:
case errInvalidRequest:
switch {
case errors.Contains(err, nil):
case errors.Contains(err, errInvalidRequest):
w.WriteHeader(http.StatusBadRequest)
case errUnauthorizedAccess:
case errors.Contains(err, errUnauthorizedAccess):
w.WriteHeader(http.StatusForbidden)
default:
w.WriteHeader(http.StatusInternalServerError)
}
errorVal, ok := err.(errors.Error)
if ok {
w.Header().Set("Content-Type", contentType)
if err := json.NewEncoder(w).Encode(errorRes{Err: errorVal.Msg()}); err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
}
}
func authorize(r *http.Request, chanID string) error {

View File

@ -7,10 +7,13 @@ import (
"fmt"
"github.com/gocql/gocql"
"github.com/mainflux/mainflux/errors"
"github.com/mainflux/mainflux/readers"
"github.com/mainflux/mainflux/transformers/senml"
)
var errReadMessages = errors.New("faled to read messages from cassandra database")
var _ readers.MessageRepository = (*cassandraRepository)(nil)
type cassandraRepository struct {
@ -59,13 +62,13 @@ func (cr cassandraRepository) ReadAll(chanID string, offset, limit uint64, query
&msg.Name, &msg.Unit, &msg.Value, &msg.StringValue, &msg.BoolValue,
&msg.DataValue, &msg.Sum, &msg.Time, &msg.UpdateTime)
if err != nil {
return readers.MessagesPage{}, err
return readers.MessagesPage{}, errors.Wrap(errReadMessages, err)
}
page.Messages = append(page.Messages, msg)
}
if err := cr.session.Query(countCQL, vals[:len(vals)-1]...).Scan(&page.Total); err != nil {
return readers.MessagesPage{}, err
return readers.MessagesPage{}, errors.Wrap(errReadMessages, err)
}
return page, nil

View File

@ -8,6 +8,7 @@ import (
"strings"
"time"
"github.com/mainflux/mainflux/errors"
"github.com/mainflux/mainflux/readers"
influxdata "github.com/influxdata/influxdb/client/v2"
@ -16,6 +17,8 @@ import (
const countCol = "count"
var errReadMessages = errors.New("faled to read messages from influxdb database")
var _ readers.MessageRepository = (*influxRepository)(nil)
type influxRepository struct {
@ -43,10 +46,10 @@ func (repo *influxRepository) ReadAll(chanID string, offset, limit uint64, query
resp, err := repo.client.Query(q)
if err != nil {
return readers.MessagesPage{}, err
return readers.MessagesPage{}, errors.Wrap(errReadMessages, err)
}
if resp.Error() != nil {
return readers.MessagesPage{}, resp.Error()
return readers.MessagesPage{}, errors.Wrap(errReadMessages, resp.Error())
}
if len(resp.Results) < 1 || len(resp.Results[0].Series) < 1 {
@ -60,7 +63,7 @@ func (repo *influxRepository) ReadAll(chanID string, offset, limit uint64, query
total, err := repo.count(condition)
if err != nil {
return readers.MessagesPage{}, err
return readers.MessagesPage{}, errors.Wrap(errReadMessages, err)
}
return readers.MessagesPage{

View File

@ -6,6 +6,7 @@ package mongodb
import (
"context"
"github.com/mainflux/mainflux/errors"
"github.com/mainflux/mainflux/readers"
"github.com/mainflux/mainflux/transformers/senml"
"go.mongodb.org/mongo-driver/bson"
@ -15,6 +16,8 @@ import (
const collection = "mainflux"
var errReadMessages = errors.New("faled to read messages from mongodb database")
var _ readers.MessageRepository = (*mongoRepository)(nil)
type mongoRepository struct {
@ -54,7 +57,7 @@ func (repo mongoRepository) ReadAll(chanID string, offset, limit uint64, query m
filter := fmtCondition(chanID, query)
cursor, err := col.Find(context.Background(), filter, options.Find().SetSort(sortMap).SetLimit(int64(limit)).SetSkip(int64(offset)))
if err != nil {
return readers.MessagesPage{}, err
return readers.MessagesPage{}, errors.Wrap(errReadMessages, err)
}
defer cursor.Close(context.Background())
@ -62,7 +65,7 @@ func (repo mongoRepository) ReadAll(chanID string, offset, limit uint64, query m
for cursor.Next(context.Background()) {
var m message
if err := cursor.Decode(&m); err != nil {
return readers.MessagesPage{}, err
return readers.MessagesPage{}, errors.Wrap(errReadMessages, err)
}
msg := senml.Message{
@ -93,7 +96,7 @@ func (repo mongoRepository) ReadAll(chanID string, offset, limit uint64, query m
total, err := col.CountDocuments(context.Background(), filter)
if err != nil {
return readers.MessagesPage{}, err
return readers.MessagesPage{}, errors.Wrap(errReadMessages, err)
}
if total < 0 {
return readers.MessagesPage{}, nil

View File

@ -4,17 +4,17 @@
package postgres
import (
"errors"
"fmt"
"github.com/jmoiron/sqlx" // required for DB access
"github.com/mainflux/mainflux/errors"
"github.com/mainflux/mainflux/readers"
"github.com/mainflux/mainflux/transformers/senml"
)
const errInvalid = "invalid_text_representation"
var errInvalidMessage = errors.New("invalid message representation")
var errReadMessages = errors.New("faled to read messages from postgres database")
var _ readers.MessageRepository = (*postgresRepository)(nil)
@ -46,7 +46,7 @@ func (tr postgresRepository) ReadAll(chanID string, offset, limit uint64, query
rows, err := tr.db.NamedQuery(q, params)
if err != nil {
return readers.MessagesPage{}, err
return readers.MessagesPage{}, errors.Wrap(errReadMessages, err)
}
defer rows.Close()
@ -58,7 +58,7 @@ func (tr postgresRepository) ReadAll(chanID string, offset, limit uint64, query
for rows.Next() {
dbm := dbMessage{Channel: chanID}
if err := rows.StructScan(&dbm); err != nil {
return readers.MessagesPage{}, err
return readers.MessagesPage{}, errors.Wrap(errReadMessages, err)
}
msg := toMessage(dbm)
@ -74,7 +74,7 @@ func (tr postgresRepository) ReadAll(chanID string, offset, limit uint64, query
}
if err := tr.db.QueryRow(q, qParams...).Scan(&page.Total); err != nil {
return readers.MessagesPage{}, err
return readers.MessagesPage{}, errors.Wrap(errReadMessages, err)
}
return page, nil

View File

@ -5,10 +5,16 @@ package senml
import (
"github.com/mainflux/mainflux/broker"
"github.com/mainflux/mainflux/errors"
"github.com/mainflux/mainflux/transformers"
"github.com/mainflux/senml"
)
var (
errDecode = errors.New("failed to decode senml")
errNormalize = errors.New("faled to normalize senml")
)
var formats = map[string]senml.Format{
JSON: senml.JSON,
CBOR: senml.CBOR,
@ -29,12 +35,12 @@ func (n transformer) Transform(msg broker.Message) (interface{}, error) {
raw, err := senml.Decode(msg.Payload, format)
if err != nil {
return nil, err
return nil, errors.Wrap(errDecode, err)
}
normalized, err := senml.Normalize(raw)
if err != nil {
return nil, err
return nil, errors.Wrap(errNormalize, err)
}
msgs := make([]Message, len(normalized.Records))

View File

@ -9,6 +9,7 @@ import (
"testing"
"github.com/mainflux/mainflux/broker"
"github.com/mainflux/mainflux/errors"
"github.com/mainflux/mainflux/transformers/senml"
mfsenml "github.com/mainflux/senml"
"github.com/stretchr/testify/assert"
@ -102,6 +103,6 @@ func TestTransform(t *testing.T) {
for _, tc := range cases {
msgs, err := tr.Transform(tc.msg)
assert.Equal(t, tc.msgs, msgs, fmt.Sprintf("%s expected %v, got %v", tc.desc, tc.msgs, msgs))
assert.Equal(t, tc.err, err, fmt.Sprintf("%s expected %s, got %s", tc.desc, tc.err, err))
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s expected %s, got %s", tc.desc, tc.err, err))
}
}

View File

@ -5,10 +5,13 @@ package cassandra
import (
"github.com/gocql/gocql"
"github.com/mainflux/mainflux/errors"
"github.com/mainflux/mainflux/transformers/senml"
"github.com/mainflux/mainflux/writers"
)
var errSaveMessage = errors.New("faled to save message to cassandra database")
var _ writers.MessageRepository = (*cassandraRepository)(nil)
type cassandraRepository struct {
@ -32,7 +35,7 @@ func (cr *cassandraRepository) Save(messages ...senml.Message) error {
msg.Protocol, msg.Name, msg.Unit, msg.Value, msg.StringValue,
msg.BoolValue, msg.DataValue, msg.Sum, msg.Time, msg.UpdateTime).Exec()
if err != nil {
return err
return errors.Wrap(errSaveMessage, err)
}
}

View File

@ -8,6 +8,7 @@ import (
"strconv"
"time"
"github.com/mainflux/mainflux/errors"
"github.com/mainflux/mainflux/transformers/senml"
"github.com/mainflux/mainflux/writers"
@ -16,6 +17,8 @@ import (
const pointName = "messages"
var errSaveMessage = errors.New("faled to save message to influxdb database")
var _ writers.MessageRepository = (*influxRepo)(nil)
type influxRepo struct {
@ -39,7 +42,7 @@ func New(client influxdata.Client, database string) writers.MessageRepository {
func (repo *influxRepo) Save(messages ...senml.Message) error {
pts, err := influxdata.NewBatchPoints(repo.cfg)
if err != nil {
return err
return errors.Wrap(errSaveMessage, err)
}
for _, msg := range messages {
@ -50,12 +53,14 @@ func (repo *influxRepo) Save(messages ...senml.Message) error {
pt, err := influxdata.NewPoint(pointName, tgs, flds, t)
if err != nil {
return err
return errors.Wrap(errSaveMessage, err)
}
pts.AddPoint(pt)
}
return repo.client.Write(pts)
if err := repo.client.Write(pts); err != nil {
return errors.Wrap(errSaveMessage, err)
}
return nil
}
func (repo *influxRepo) tagsOf(msg *senml.Message) tags {

View File

@ -8,12 +8,15 @@ import (
"go.mongodb.org/mongo-driver/mongo"
"github.com/mainflux/mainflux/errors"
"github.com/mainflux/mainflux/transformers/senml"
"github.com/mainflux/mainflux/writers"
)
const collectionName string = "mainflux"
var errSaveMessage = errors.New("faled to save message to mongodb database")
var _ writers.MessageRepository = (*mongoRepo)(nil)
type mongoRepo struct {
@ -73,5 +76,8 @@ func (repo *mongoRepo) Save(messages ...senml.Message) error {
}
_, err := coll.InsertMany(context.Background(), msgs)
return err
if err != nil {
return errors.Wrap(errSaveMessage, err)
}
return nil
}

View File

@ -5,21 +5,23 @@ package postgres
import (
"context"
"errors"
"github.com/gofrs/uuid"
"github.com/jmoiron/sqlx"
"github.com/lib/pq" // required for DB access
"github.com/mainflux/mainflux/errors"
"github.com/mainflux/mainflux/transformers/senml"
"github.com/mainflux/mainflux/writers"
)
const errInvalid = "invalid_text_representation"
// ErrInvalidMessage indicates that service received message that
// doesn't fit required format.
var ErrInvalidMessage = errors.New("invalid message representation")
var (
// ErrInvalidMessage indicates that service received message that
// doesn't fit required format.
ErrInvalidMessage = errors.New("invalid message representation")
errSaveMessage = errors.New("faled to save message to postgress database")
)
var _ writers.MessageRepository = (*postgresRepo)(nil)
@ -42,13 +44,13 @@ func (pr postgresRepo) Save(messages ...senml.Message) error {
tx, err := pr.db.BeginTxx(context.Background(), nil)
if err != nil {
return err
return errors.Wrap(errSaveMessage, err)
}
for _, msg := range messages {
dbth, err := toDBMessage(msg)
if err != nil {
return err
return errors.Wrap(errSaveMessage, err)
}
if _, err := tx.NamedExec(q, dbth); err != nil {
@ -56,15 +58,17 @@ func (pr postgresRepo) Save(messages ...senml.Message) error {
if ok {
switch pqErr.Code.Name() {
case errInvalid:
return ErrInvalidMessage
return errors.Wrap(errSaveMessage, ErrInvalidMessage)
}
}
return err
return errors.Wrap(errSaveMessage, err)
}
}
return tx.Commit()
if err := tx.Commit(); err != nil {
return errors.Wrap(errSaveMessage, err)
}
return nil
}
type dbMessage struct {