Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-pages.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/grpc-ecosystem/go-grpc-middleware/tags/fieldextractor.go')
-rw-r--r--vendor/github.com/grpc-ecosystem/go-grpc-middleware/tags/fieldextractor.go85
1 files changed, 85 insertions, 0 deletions
diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/tags/fieldextractor.go b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/tags/fieldextractor.go
new file mode 100644
index 00000000..d87ee438
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/tags/fieldextractor.go
@@ -0,0 +1,85 @@
+// Copyright 2017 Michal Witkowski. All Rights Reserved.
+// See LICENSE for licensing terms.
+
+package grpc_ctxtags
+
+import (
+ "reflect"
+)
+
+// RequestFieldExtractorFunc is a user-provided function that extracts field information from a gRPC request.
+// It is called from tags middleware on arrival of unary request or a server-stream request.
+// Keys and values will be added to the context tags of the request. If there are no fields, you should return a nil.
+type RequestFieldExtractorFunc func(fullMethod string, req interface{}) map[string]interface{}
+
+type requestFieldsExtractor interface {
+ // ExtractRequestFields is a method declared on a Protobuf message that extracts fields from the interface.
+ // The values from the extracted fields should be set in the appendToMap, in order to avoid allocations.
+ ExtractRequestFields(appendToMap map[string]interface{})
+}
+
+// CodeGenRequestFieldExtractor is a function that relies on code-generated functions that export log fields from requests.
+// These are usually coming from a protoc-plugin that generates additional information based on custom field options.
+func CodeGenRequestFieldExtractor(fullMethod string, req interface{}) map[string]interface{} {
+ if ext, ok := req.(requestFieldsExtractor); ok {
+ retMap := make(map[string]interface{})
+ ext.ExtractRequestFields(retMap)
+ if len(retMap) == 0 {
+ return nil
+ }
+ return retMap
+ }
+ return nil
+}
+
+// TagBasedRequestFieldExtractor is a function that relies on Go struct tags to export log fields from requests.
+// These are usualy coming from a protoc-plugin, such as Gogo protobuf.
+//
+// message Metadata {
+// repeated string tags = 1 [ (gogoproto.moretags) = "log_field:\"meta_tags\"" ];
+// }
+//
+// The tagName is configurable using the tagName variable. Here it would be "log_field".
+func TagBasedRequestFieldExtractor(tagName string) RequestFieldExtractorFunc {
+ return func(fullMethod string, req interface{}) map[string]interface{} {
+ retMap := make(map[string]interface{})
+ reflectMessageTags(req, retMap, tagName)
+ if len(retMap) == 0 {
+ return nil
+ }
+ return retMap
+ }
+}
+
+func reflectMessageTags(msg interface{}, existingMap map[string]interface{}, tagName string) {
+ v := reflect.ValueOf(msg)
+ // Only deal with pointers to structs.
+ if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct {
+ return
+ }
+ // Deref the pointer get to the struct.
+ v = v.Elem()
+ t := v.Type()
+ for i := 0; i < v.NumField(); i++ {
+ field := v.Field(i)
+ kind := field.Kind()
+ // Only recurse down direct pointers, which should only be to nested structs.
+ if kind == reflect.Ptr {
+ reflectMessageTags(field.Interface(), existingMap, tagName)
+ }
+ // In case of arrays/splices (repeated fields) go down to the concrete type.
+ if kind == reflect.Array || kind == reflect.Slice {
+ if field.Len() == 0 {
+ continue
+ }
+ kind = field.Index(0).Kind()
+ }
+ // Only be interested in
+ if (kind >= reflect.Bool && kind <= reflect.Float64) || kind == reflect.String {
+ if tag := t.Field(i).Tag.Get(tagName); tag != "" {
+ existingMap[tag] = field.Interface()
+ }
+ }
+ }
+ return
+}