| /* |
| * Copyright 2020-2024 Open Networking Foundation (ONF) and the ONF Contributors |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| // Package olterrors implements functions to manipulate OLT errors |
| package olterrors |
| |
| import ( |
| "context" |
| "encoding/json" |
| "fmt" |
| "strings" |
| |
| "github.com/opencord/voltha-lib-go/v7/pkg/log" |
| ) |
| |
| const ( |
| defaultLogAndReturnLevel = log.ErrorLevel |
| ) |
| |
| func copy(src log.Fields) log.Fields { |
| dst := make(log.Fields) |
| for k, v := range src { |
| dst[k] = v |
| } |
| return dst |
| } |
| |
| func merge(one, two log.Fields) log.Fields { |
| dst := make(log.Fields) |
| for k, v := range one { |
| dst[k] = v |
| } |
| for k, v := range two { |
| dst[k] = v |
| } |
| return dst |
| } |
| |
| // LoggableError defined functions that can be used to log an object |
| type LoggableError interface { |
| error |
| Log() error |
| LogAt(log.LogLevel) error |
| } |
| |
| // WrappedError can be used to extract the wrapped errors of structs that include ErrAdapter |
| type WrappedError interface { |
| Unwrap() error |
| } |
| |
| // ErrAdapter represents a basic adapter error that combines an name, field set |
| // and wrapped error |
| type ErrAdapter struct { |
| name string |
| fields log.Fields |
| wrapped error |
| } |
| |
| // NewErrAdapter constructs a new error with the given values |
| func NewErrAdapter(name string, fields log.Fields, wrapped error) LoggableError { |
| return &ErrAdapter{ |
| name: name, |
| fields: copy(fields), |
| wrapped: wrapped, |
| } |
| } |
| |
| // Name returns the error name |
| func (e *ErrAdapter) Name() string { |
| return e.name |
| } |
| |
| // Fields returns the fields associated with the error |
| func (e *ErrAdapter) Fields() log.Fields { |
| return e.fields |
| } |
| |
| // Unwrap returns the wrapped or nested error |
| func (e *ErrAdapter) Unwrap() error { |
| return e.wrapped |
| } |
| |
| // Error returns a string representation of the error |
| func (e *ErrAdapter) Error() string { |
| ctx := context.Background() |
| var buf strings.Builder |
| _, er := buf.WriteString(e.name) |
| if er != nil { |
| logger.Error(ctx, er) |
| } |
| if len(e.fields) > 0 { |
| if val, err := json.Marshal(e.fields); err == nil { |
| _, er = buf.WriteString(fmt.Sprintf(": [%s]", string(val))) |
| if er != nil { |
| logger.Error(ctx, er) |
| } |
| } |
| } |
| if e.wrapped != nil { |
| _, er = buf.WriteString(fmt.Sprintf(": %s", e.wrapped.Error())) |
| if er != nil { |
| logger.Error(ctx, er) |
| } |
| } |
| return buf.String() |
| } |
| |
| // Log logs the error at the default level for log and return |
| func (e *ErrAdapter) Log() error { |
| return e.LogAt(defaultLogAndReturnLevel) |
| } |
| |
| // LogAt logs the error at the specified level and then returns the error |
| func (e *ErrAdapter) LogAt(level log.LogLevel) error { |
| loggerFunc := logger.Debugw |
| switch level { |
| case log.InfoLevel: |
| loggerFunc = logger.Infow |
| case log.WarnLevel: |
| loggerFunc = logger.Warnw |
| case log.ErrorLevel: |
| loggerFunc = logger.Errorw |
| case log.FatalLevel: |
| loggerFunc = logger.Fatalw |
| } |
| local := e.fields |
| if e.wrapped != nil { |
| local = merge(e.fields, log.Fields{"wrapped": e.wrapped}) |
| } |
| loggerFunc(context.Background(), e.name, local) |
| return e |
| } |
| |
| // ErrInvalidValue represents an error condition with given value is not able to |
| // be processed |
| type ErrInvalidValue struct { |
| ErrAdapter |
| } |
| |
| // NewErrInvalidValue constructs a new error based on the given values |
| func NewErrInvalidValue(fields log.Fields, wrapped error) LoggableError { |
| return &ErrInvalidValue{ |
| ErrAdapter{ |
| name: "invalid-value", |
| fields: copy(fields), |
| wrapped: wrapped, |
| }, |
| } |
| } |
| |
| // Log logs the error at the default level for log and return |
| func (e *ErrInvalidValue) Log() error { |
| _ = e.ErrAdapter.Log() |
| return e |
| } |
| |
| // LogAt logs the error at the specified level and then returns the error |
| func (e *ErrInvalidValue) LogAt(level log.LogLevel) error { |
| _ = e.ErrAdapter.LogAt(level) |
| return e |
| } |
| |
| // ErrNotFound represents an error condition when a value can not be located |
| // given a field set of criteria |
| type ErrNotFound struct { |
| ErrAdapter |
| } |
| |
| // NewErrNotFound constructs a new error based on the given values |
| func NewErrNotFound(target string, fields log.Fields, wrapped error) LoggableError { |
| return &ErrNotFound{ |
| ErrAdapter{ |
| name: "not-found", |
| fields: merge(fields, log.Fields{"target": target}), |
| wrapped: wrapped, |
| }, |
| } |
| } |
| |
| // Log logs the error at the default level for log and return |
| func (e *ErrNotFound) Log() error { |
| _ = e.ErrAdapter.Log() |
| return e |
| } |
| |
| // LogAt logs the error at the specified level and then returns the error |
| func (e *ErrNotFound) LogAt(level log.LogLevel) error { |
| _ = e.ErrAdapter.LogAt(level) |
| return e |
| } |
| |
| // ErrPersistence representation an error condition when a persistence operation |
| // did not succeed |
| type ErrPersistence struct { |
| ErrAdapter |
| } |
| |
| // NewErrPersistence constructs a new error based on the given values |
| func NewErrPersistence(operation, entityType string, ID uint64, fields log.Fields, wrapped error) LoggableError { |
| return &ErrPersistence{ |
| ErrAdapter{ |
| name: "unable-to-persist", |
| fields: merge(fields, log.Fields{ |
| "operation": operation, |
| "entity-type": entityType, |
| "id": fmt.Sprintf("0x%x", ID)}), |
| wrapped: wrapped, |
| }, |
| } |
| } |
| |
| // Log logs the error at the default level for log and return |
| func (e *ErrPersistence) Log() error { |
| _ = e.ErrAdapter.Log() |
| return e |
| } |
| |
| // LogAt logs the error at the specified level and then returns the error |
| func (e *ErrPersistence) LogAt(level log.LogLevel) error { |
| _ = e.ErrAdapter.LogAt(level) |
| return e |
| } |
| |
| // ErrCommunication representation an error condition when an interprocess |
| // message communication fails |
| type ErrCommunication struct { |
| ErrAdapter |
| } |
| |
| // NewErrCommunication constructs a new error based on the given values |
| func NewErrCommunication(operation string, fields log.Fields, wrapped error) LoggableError { |
| return &ErrCommunication{ |
| ErrAdapter{ |
| name: "failed-communication", |
| fields: merge(fields, log.Fields{ |
| "operation": operation}), |
| wrapped: wrapped, |
| }, |
| } |
| } |
| |
| // Log logs the error at the default level for log and return |
| func (e *ErrCommunication) Log() error { |
| _ = e.ErrAdapter.Log() |
| return e |
| } |
| |
| // LogAt logs the error at the specified level and then returns the error |
| func (e *ErrCommunication) LogAt(level log.LogLevel) error { |
| _ = e.ErrAdapter.LogAt(level) |
| return e |
| } |
| |
| // ErrFlowOp represents an error condition when a flow operation to a device did |
| // not succeed |
| type ErrFlowOp struct { |
| ErrAdapter |
| } |
| |
| // NewErrFlowOp constructs a new error based on the given values |
| func NewErrFlowOp(operation string, ID uint64, fields log.Fields, wrapped error) LoggableError { |
| return &ErrPersistence{ |
| ErrAdapter{ |
| name: "unable-to-perform-flow-operation", |
| fields: merge(fields, log.Fields{ |
| "operation": operation, |
| "id": fmt.Sprintf("0x%x", ID)}), |
| wrapped: wrapped, |
| }, |
| } |
| } |
| |
| // Log logs the error at the default level for log and return |
| func (e *ErrFlowOp) Log() error { |
| _ = e.ErrAdapter.Log() |
| return e |
| } |
| |
| // LogAt logs the error at the specified level and then returns the error |
| func (e *ErrFlowOp) LogAt(level log.LogLevel) error { |
| _ = e.ErrAdapter.LogAt(level) |
| return e |
| } |
| |
| // ErrGroupOp represents an error condition when a group operation to a device did |
| // not succeed |
| type ErrGroupOp struct { |
| ErrAdapter |
| } |
| |
| // NewErrGroupOp constructs a new error based on the given values |
| func NewErrGroupOp(operation string, ID uint32, fields log.Fields, wrapped error) LoggableError { |
| return &ErrPersistence{ |
| ErrAdapter{ |
| name: "unable-to-perform-group-operation", |
| fields: merge(fields, log.Fields{ |
| "operation": operation, |
| "id": fmt.Sprintf("0x%x", ID)}), |
| wrapped: wrapped, |
| }, |
| } |
| } |
| |
| // Log logs the error at the default level for log and return |
| func (e *ErrGroupOp) Log() error { |
| _ = e.ErrAdapter.Log() |
| return e |
| } |
| |
| // LogAt logs the error at the specified level and then returns the error |
| func (e *ErrGroupOp) LogAt(level log.LogLevel) error { |
| _ = e.ErrAdapter.LogAt(level) |
| return e |
| } |
| |
| // ErrTimeout represents an error condition when the deadline for performing an |
| // operation has been exceeded |
| type ErrTimeout struct { |
| ErrAdapter |
| } |
| |
| // NewErrTimeout constructs a new error based on the given values |
| func NewErrTimeout(operation string, fields log.Fields, wrapped error) LoggableError { |
| return &ErrTimeout{ |
| ErrAdapter{ |
| name: "operation-timed-out", |
| fields: merge(fields, log.Fields{"operation": operation}), |
| wrapped: wrapped, |
| }, |
| } |
| } |
| |
| // Log logs the error at the default level for log and return |
| func (e *ErrTimeout) Log() error { |
| _ = e.ErrAdapter.Log() |
| return e |
| } |
| |
| // LogAt logs the error at the specified level and then returns the error |
| func (e *ErrTimeout) LogAt(level log.LogLevel) error { |
| _ = e.ErrAdapter.LogAt(level) |
| return e |
| } |
| |
| var ( |
| // ErrNotImplemented error returned when an unimplemented method is |
| // invoked |
| ErrNotImplemented = NewErrAdapter("not-implemented", nil, nil) |
| |
| // ErrInvalidPortRange error returned when a given port is not in the |
| // valid range |
| ErrInvalidPortRange = NewErrAdapter("invalid-port-range", nil, nil) |
| |
| // ErrStateTransition error returned when a state transition is fails |
| ErrStateTransition = NewErrAdapter("state-transition", nil, nil) |
| |
| // ErrResourceManagerInstantiating error returned when an unexpected |
| // condition occcurs while instantiating the resource manager |
| ErrResourceManagerInstantiating = NewErrAdapter("resoure-manager-instantiating", nil, nil) |
| |
| // ErrFlowManagerInstantiating error returned when an unexpected |
| // condition occcurs while instantiating the flow manager |
| ErrFlowManagerInstantiating = NewErrAdapter("flow-manager-instantiating", nil, nil) |
| |
| // ErrGroupManagerInstantiating error returned when an unexpected |
| // condition occcurs while instantiating the group manager |
| ErrGroupManagerInstantiating = NewErrAdapter("group-manager-instantiating", nil, nil) |
| ) |