move recorder to interface
This commit is contained in:
		
							
								
								
									
										75
									
								
								pkg/weather/recorder/recorders/memory/get.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								pkg/weather/recorder/recorders/memory/get.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,75 @@ | ||||
| package memory | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"errors" | ||||
| 	"slices" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/attribute" | ||||
| 	"go.opentelemetry.io/otel/codes" | ||||
|  | ||||
| 	pb "gitea.libretechconsulting.com/rmcguire/ambient-local-exporter/api/v1alpha1/weather" | ||||
| 	"gitea.libretechconsulting.com/rmcguire/ambient-local-exporter/pkg/weather" | ||||
| ) | ||||
|  | ||||
| func (r *MemoryRecorder) Get(ctx context.Context, req *pb.GetWeatherRequest) ( | ||||
| 	[]*weather.WeatherUpdate, error, | ||||
| ) { | ||||
| 	ctx, span := r.tracer.Start(ctx, "memoryRecorder.Get") | ||||
| 	defer span.End() | ||||
|  | ||||
| 	r.RLock() | ||||
| 	defer r.RUnlock() | ||||
|  | ||||
| 	span.AddEvent("acquired lock on recorder cache") | ||||
|  | ||||
| 	updates := r.updates | ||||
|  | ||||
| 	if r.count() == 0 { | ||||
| 		err := errors.New("no recorded updates to get") | ||||
| 		span.RecordError(err) | ||||
| 		return nil, err | ||||
| 	} else if r.count() <= int(*req.Limit) { | ||||
| 		span.RecordError(errors.New("requested more updates than recorded")) | ||||
| 	} | ||||
|  | ||||
| 	// Filter by Station Name if requested | ||||
| 	if req.Opts.StationName != nil && *req.Opts.StationName != "" { | ||||
| 		updates = slices.DeleteFunc(updates, func(u *weather.WeatherUpdate) bool { | ||||
| 			return u.StationConfig == nil || u.StationConfig.Name != *req.Opts.StationName | ||||
| 		}) | ||||
| 	} | ||||
|  | ||||
| 	// Filter by Station Type if requested | ||||
| 	if req.Opts.StationType != nil && *req.Opts.StationType != "" { | ||||
| 		updates = slices.DeleteFunc(updates, func(u *weather.WeatherUpdate) bool { | ||||
| 			return u.StationType == nil || *u.StationType != *req.Opts.StationType | ||||
| 		}) | ||||
| 	} | ||||
|  | ||||
| 	// Limit results | ||||
| 	if len(updates) > int(*req.Limit) { | ||||
| 		updates = updates[len(updates)-int(*req.Limit):] | ||||
| 	} | ||||
|  | ||||
| 	span.SetAttributes(attribute.Int("retrieved", len(updates))) | ||||
| 	span.SetStatus(codes.Ok, "") | ||||
|  | ||||
| 	return updates, nil | ||||
| } | ||||
|  | ||||
| func (r *MemoryRecorder) Count(ctx context.Context) int { | ||||
| 	_, span := r.tracer.Start(ctx, "countWeatherRecorder") | ||||
| 	defer span.End() | ||||
|  | ||||
| 	count := r.count() | ||||
|  | ||||
| 	span.SetAttributes(attribute.Int("count", count)) | ||||
| 	span.SetStatus(codes.Ok, "") | ||||
|  | ||||
| 	return count | ||||
| } | ||||
|  | ||||
| func (r *MemoryRecorder) count() int { | ||||
| 	return len(r.updates) | ||||
| } | ||||
							
								
								
									
										35
									
								
								pkg/weather/recorder/recorders/memory/memory.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								pkg/weather/recorder/recorders/memory/memory.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| package memory | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"sync" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/trace" | ||||
|  | ||||
| 	"gitea.libretechconsulting.com/rmcguire/go-app/pkg/otel" | ||||
|  | ||||
| 	"gitea.libretechconsulting.com/rmcguire/ambient-local-exporter/pkg/weather" | ||||
| 	"gitea.libretechconsulting.com/rmcguire/ambient-local-exporter/pkg/weather/recorder/recorders" | ||||
| ) | ||||
|  | ||||
| const defRetainLast = 120 | ||||
|  | ||||
| type MemoryRecorder struct { | ||||
| 	baseCtx context.Context | ||||
| 	updates []*weather.WeatherUpdate | ||||
| 	tracer  trace.Tracer | ||||
| 	keep    int | ||||
| 	*sync.RWMutex | ||||
| } | ||||
|  | ||||
| func (r *MemoryRecorder) Init(ctx context.Context, opts *recorders.RecorderOpts) { | ||||
| 	if opts.RetainLast < 1 { | ||||
| 		opts.RetainLast = defRetainLast | ||||
| 	} | ||||
|  | ||||
| 	r.updates = make([]*weather.WeatherUpdate, 0, opts.RetainLast) | ||||
| 	r.keep = opts.RetainLast | ||||
| 	r.baseCtx = opts.BaseCtx | ||||
| 	r.RWMutex = &sync.RWMutex{} | ||||
| 	r.tracer = otel.GetTracer(r.baseCtx, "memoryRecorder") | ||||
| } | ||||
							
								
								
									
										38
									
								
								pkg/weather/recorder/recorders/memory/set.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								pkg/weather/recorder/recorders/memory/set.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| package memory | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/attribute" | ||||
| 	"go.opentelemetry.io/otel/trace" | ||||
|  | ||||
| 	"gitea.libretechconsulting.com/rmcguire/ambient-local-exporter/pkg/weather" | ||||
| ) | ||||
|  | ||||
| func (r *MemoryRecorder) Set(ctx context.Context, u *weather.WeatherUpdate) error { | ||||
| 	r.Lock() | ||||
| 	defer r.Unlock() | ||||
|  | ||||
| 	ctx, span := r.tracer.Start(ctx, "memoryRecorder.Set") | ||||
| 	span.SetAttributes( | ||||
| 		attribute.Int("countWeatherUpdates", r.Count(ctx)), | ||||
| 		attribute.Int("keepUpdates", r.keep), | ||||
| 	) | ||||
| 	defer span.End() | ||||
|  | ||||
| 	return r.set(ctx, u) | ||||
| } | ||||
|  | ||||
| func (r *MemoryRecorder) set(ctx context.Context, u *weather.WeatherUpdate) error { | ||||
| 	span := trace.SpanFromContext(ctx) | ||||
|  | ||||
| 	if len(r.updates) > r.keep { | ||||
| 		r.updates = r.updates[1:] | ||||
| 		span.AddEvent("trimmed recorded updates by 1") | ||||
| 	} | ||||
|  | ||||
| 	r.updates = append(r.updates, u) | ||||
| 	span.AddEvent("recorded weather update") | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										20
									
								
								pkg/weather/recorder/recorders/recorders.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								pkg/weather/recorder/recorders/recorders.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| package recorders | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
|  | ||||
| 	pb "gitea.libretechconsulting.com/rmcguire/ambient-local-exporter/api/v1alpha1/weather" | ||||
| 	"gitea.libretechconsulting.com/rmcguire/ambient-local-exporter/pkg/weather" | ||||
| ) | ||||
|  | ||||
| type RecorderOpts struct { | ||||
| 	RetainLast int | ||||
| 	BaseCtx    context.Context | ||||
| } | ||||
|  | ||||
| type Recorder interface { | ||||
| 	Init(context.Context, *RecorderOpts) | ||||
| 	Set(context.Context, *weather.WeatherUpdate) error | ||||
| 	Get(context.Context, *pb.GetWeatherRequest) ([]*weather.WeatherUpdate, error) | ||||
| 	Count(context.Context) int // Best Effort | ||||
| } | ||||
		Reference in New Issue
	
	Block a user