github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/aggregator/server/m3msg/server.go (about)

     1  // Copyright (c) 2020 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package m3msg
    22  
    23  import (
    24  	"fmt"
    25  
    26  	"github.com/m3db/m3/src/aggregator/aggregator"
    27  	"github.com/m3db/m3/src/metrics/encoding"
    28  	"github.com/m3db/m3/src/metrics/encoding/protobuf"
    29  	"github.com/m3db/m3/src/metrics/generated/proto/metricpb"
    30  	"github.com/m3db/m3/src/msg/consumer"
    31  	xserver "github.com/m3db/m3/src/x/server"
    32  
    33  	"go.uber.org/zap"
    34  )
    35  
    36  // NewServer creates a new M3Msg server.
    37  func NewServer(
    38  	address string,
    39  	aggregator aggregator.Aggregator,
    40  	opts Options,
    41  ) (xserver.Server, error) {
    42  	if err := opts.Validate(); err != nil {
    43  		return nil, err
    44  	}
    45  	newMessageProcessor := func() consumer.MessageProcessor {
    46  		// construct a new messageProcessor per consumer so the internal protos can be reused across messages on the
    47  		// same connection.
    48  		return &messageProcessor{
    49  			aggregator: aggregator,
    50  			logger:     opts.InstrumentOptions().Logger(),
    51  		}
    52  	}
    53  	handler := consumer.NewMessageHandler(consumer.NewMessageProcessorFactory(newMessageProcessor), opts.ConsumerOptions())
    54  	return xserver.NewServer(address, handler, opts.ServerOptions()), nil
    55  }
    56  
    57  type messageProcessor struct {
    58  	pb         metricpb.MetricWithMetadatas
    59  	union      encoding.UnaggregatedMessageUnion
    60  	aggregator aggregator.Aggregator
    61  	logger     *zap.Logger
    62  }
    63  
    64  func (m *messageProcessor) Process(msg consumer.Message) {
    65  	if err := m.handleMessage(&m.pb, &m.union, msg); err != nil {
    66  		m.logger.Error("could not process message",
    67  			zap.Error(err),
    68  			zap.Uint64("shard", msg.ShardID()),
    69  			zap.String("proto", m.pb.String()))
    70  	}
    71  }
    72  
    73  func (m *messageProcessor) handleMessage(
    74  	pb *metricpb.MetricWithMetadatas,
    75  	union *encoding.UnaggregatedMessageUnion,
    76  	msg consumer.Message,
    77  ) error {
    78  	defer msg.Ack()
    79  
    80  	// Reset and reuse the protobuf message for unpacking.
    81  	protobuf.ReuseMetricWithMetadatasProto(&m.pb)
    82  	// Unmarshal the message.
    83  	if err := pb.Unmarshal(msg.Bytes()); err != nil {
    84  		return err
    85  	}
    86  
    87  	switch pb.Type {
    88  	case metricpb.MetricWithMetadatas_COUNTER_WITH_METADATAS:
    89  		err := union.CounterWithMetadatas.FromProto(pb.CounterWithMetadatas)
    90  		if err != nil {
    91  			return err
    92  		}
    93  		u := union.CounterWithMetadatas.ToUnion()
    94  		return m.aggregator.AddUntimed(u, union.CounterWithMetadatas.StagedMetadatas)
    95  	case metricpb.MetricWithMetadatas_BATCH_TIMER_WITH_METADATAS:
    96  		err := union.BatchTimerWithMetadatas.FromProto(pb.BatchTimerWithMetadatas)
    97  		if err != nil {
    98  			return err
    99  		}
   100  		u := union.BatchTimerWithMetadatas.ToUnion()
   101  		return m.aggregator.AddUntimed(u, union.BatchTimerWithMetadatas.StagedMetadatas)
   102  	case metricpb.MetricWithMetadatas_GAUGE_WITH_METADATAS:
   103  		err := union.GaugeWithMetadatas.FromProto(pb.GaugeWithMetadatas)
   104  		if err != nil {
   105  			return err
   106  		}
   107  		u := union.GaugeWithMetadatas.ToUnion()
   108  		return m.aggregator.AddUntimed(u, union.GaugeWithMetadatas.StagedMetadatas)
   109  	case metricpb.MetricWithMetadatas_FORWARDED_METRIC_WITH_METADATA:
   110  		err := union.ForwardedMetricWithMetadata.FromProto(pb.ForwardedMetricWithMetadata)
   111  		if err != nil {
   112  			return err
   113  		}
   114  		return m.aggregator.AddForwarded(
   115  			union.ForwardedMetricWithMetadata.ForwardedMetric,
   116  			union.ForwardedMetricWithMetadata.ForwardMetadata)
   117  	case metricpb.MetricWithMetadatas_TIMED_METRIC_WITH_METADATA:
   118  		err := union.TimedMetricWithMetadata.FromProto(pb.TimedMetricWithMetadata)
   119  		if err != nil {
   120  			return err
   121  		}
   122  		return m.aggregator.AddTimed(
   123  			union.TimedMetricWithMetadata.Metric,
   124  			union.TimedMetricWithMetadata.TimedMetadata)
   125  	case metricpb.MetricWithMetadatas_TIMED_METRIC_WITH_METADATAS:
   126  		err := union.TimedMetricWithMetadatas.FromProto(pb.TimedMetricWithMetadatas)
   127  		if err != nil {
   128  			return err
   129  		}
   130  		return m.aggregator.AddTimedWithStagedMetadatas(
   131  			union.TimedMetricWithMetadatas.Metric,
   132  			union.TimedMetricWithMetadatas.StagedMetadatas)
   133  	default:
   134  		return fmt.Errorf("unrecognized message type: %v", pb.Type)
   135  	}
   136  }
   137  
   138  func (m *messageProcessor) Close() {}