• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

openconfig / ygot / 5049947885

22 May 2023 08:09PM UTC coverage: 88.89% (-1.2%) from 90.12%
5049947885

Pull #828

github

GitHub
Merge branch 'master' into logging-perf
Pull Request #828: perf(logging): prevent unnecessary processing for debug logging

328 of 328 new or added lines in 18 files covered. (100.0%)

12634 of 14213 relevant lines covered (88.89%)

485.08 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

83.7
/util/debug.go
1
// Copyright 2017 Google Inc.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//      http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15
package util
16

17
import (
18
        "fmt"
19
        "reflect"
20
        "strings"
21

22
        "github.com/kylelemons/godebug/pretty"
23
        "github.com/openconfig/goyang/pkg/yang"
24
)
25

26
var (
27
        // debugLibrary controls the debugging output from the library data tree
28
        // traversal. Since this setting causes global variables to be manipulated
29
        // controlling the output of the library, it MUST NOT be used in a setting
30
        // whereby thread-safety is required.
31
        debugLibrary = false
32
        // debugSchema controls the debugging output from the library from schema
33
        // matching code. Generates lots of output, so this should be used
34
        // selectively per test case.
35
        debugSchema = false
36
        // maxCharsPerLine is the maximum number of characters per line from
37
        // DbgPrint and DbgSchema. Additional characters are truncated.
38
        maxCharsPerLine = 1000
39
        // maxValueStrLen is the maximum number of characters output from ValueStr.
40
        maxValueStrLen = 150
41
)
42

43
// DebugLibraryEnabled returns the value of debugLibrary.
44
// This function is used to prevent unnecessary inline processing of the DbgPrint calls.
45
func DebugLibraryEnabled() bool {
288✔
46
        return debugLibrary
288✔
47
}
288✔
48

49
// DebugSchemaEnabled returns the value of debugSchema.
50
// This function is used to prevent unnecessary inline processing of the DbgSchema calls.
51
func DebugSchemaEnabled() bool {
355✔
52
        return debugSchema
355✔
53
}
355✔
54

55
// DbgPrint prints v if the package global variable debugLibrary is set.
56
// v has the same format as Printf. A trailing newline is added to the output.
57
func DbgPrint(v ...interface{}) {
1✔
58
        if !debugLibrary {
1✔
59
                return
×
60
        }
×
61
        out := fmt.Sprintf(v[0].(string), v[1:]...)
1✔
62
        if len(out) > maxCharsPerLine {
2✔
63
                out = out[:maxCharsPerLine]
1✔
64
        }
1✔
65
        fmt.Println(globalIndent + out)
1✔
66
}
67

68
// DbgSchema prints v if the package global variable debugSchema is set.
69
// v has the same format as Printf.
70
func DbgSchema(v ...interface{}) {
1✔
71
        if debugSchema {
2✔
72
                fmt.Printf(v[0].(string), v[1:]...)
1✔
73
        }
1✔
74
}
75

76
// DbgErr DbgPrints err and returns it.
77
func DbgErr(err error) error {
2✔
78
        if debugLibrary {
2✔
79
                DbgPrint("ERR: " + err.Error())
×
80
        }
×
81

82
        return err
2✔
83
}
84

85
// globalIndent is used to control Indent level.
86
var globalIndent = ""
87

88
// Indent increases DbgPrint Indent level.
89
func Indent() {
×
90
        if !debugLibrary {
×
91
                return
×
92
        }
×
93
        globalIndent += ". "
×
94
}
95

96
// Dedent decreases DbgPrint Indent level.
97
func Dedent() {
×
98
        if !debugLibrary {
×
99
                return
×
100
        }
×
101
        globalIndent = strings.TrimPrefix(globalIndent, ". ")
×
102
}
103

104
// ResetIndent sets the indent level to zero.
105
func ResetIndent() {
10✔
106
        if !debugLibrary {
20✔
107
                return
10✔
108
        }
10✔
109
        globalIndent = ""
×
110
}
111

112
// ValueStrDebug returns "<not calculated>" if the package global variable
113
// debugLibrary is not set. Otherwise, it is the same as ValueStr.
114
// Use this function instead of ValueStr for debugging purpose, e.g. when the
115
// output is passed to DbgPrint, because ValueStr calls can be the bottleneck
116
// for large input.
117
func ValueStrDebug(value interface{}) string {
2✔
118
        if !debugLibrary {
3✔
119
                return "<not calculated>"
1✔
120
        }
1✔
121
        return ValueStr(value)
1✔
122
}
123

124
// ValueStr returns a string representation of value which may be a value, ptr,
125
// or struct type.
126
func ValueStr(value interface{}) string {
18✔
127
        out := valueStrInternal(value)
18✔
128
        if len(out) > maxValueStrLen {
19✔
129
                out = out[:maxValueStrLen] + "..."
1✔
130
        }
1✔
131
        return out
18✔
132
}
133

134
// ValueStrInternal is the internal implementation of ValueStr.
135
func valueStrInternal(value interface{}) string {
18✔
136
        v := reflect.ValueOf(value)
18✔
137
        kind := v.Kind()
18✔
138
        switch kind {
18✔
139
        case reflect.Ptr:
1✔
140
                if v.IsNil() || !v.IsValid() {
1✔
141
                        return "nil"
×
142
                }
×
143
                return strings.Replace(ValueStr(v.Elem().Interface()), ")", " ptr)", -1)
1✔
144
        case reflect.Slice:
1✔
145
                var out string
1✔
146
                for i := 0; i < v.Len(); i++ {
4✔
147
                        if i != 0 {
5✔
148
                                out += ", "
2✔
149
                        }
2✔
150
                        out += ValueStr(v.Index(i).Interface())
3✔
151
                }
152
                return "[ " + out + " ]"
1✔
153
        case reflect.Struct:
2✔
154
                var out string
2✔
155
                for i := 0; i < v.NumField(); i++ {
6✔
156
                        if i != 0 {
7✔
157
                                out += ", "
3✔
158
                        }
3✔
159
                        if !v.Field(i).CanInterface() {
4✔
160
                                continue
×
161
                        }
162
                        out += ValueStr(v.Field(i).Interface())
4✔
163
                }
164
                return "{ " + out + " }"
2✔
165
        }
166
        out := fmt.Sprintf("%v (%v)", value, kind)
14✔
167
        if len(out) > maxValueStrLen {
14✔
168
                out = out[:maxValueStrLen] + "..."
×
169
        }
×
170
        return out
14✔
171
}
172

173
// SchemaTypeStr returns a string representation of the type of element schema
174
// represents e.g. "container", "choice" etc.
175
func SchemaTypeStr(schema *yang.Entry) string {
15✔
176
        switch {
15✔
177
        case schema.IsChoice():
1✔
178
                return "choice"
1✔
179
        case schema.IsContainer():
3✔
180
                return "container"
3✔
181
        case schema.IsCase():
1✔
182
                return "case"
1✔
183
        case schema.IsList():
3✔
184
                return "list"
3✔
185
        case schema.IsLeaf():
5✔
186
                return "leaf"
5✔
187
        case schema.IsLeafList():
1✔
188
                return "leaf-list"
1✔
189
        }
190
        return "other"
1✔
191
}
192

193
// YangTypeToDebugString returns a debug string representation of a YangType.
194
func YangTypeToDebugString(yt *yang.YangType) string {
2✔
195
        out := fmt.Sprintf("(TypeKind: %s", yang.TypeKindToName[yt.Kind])
2✔
196
        if p, isPOSIX := SanitizedPattern(yt); len(p) != 0 {
4✔
197
                out += fmt.Sprintf(", Sanitized pattern (POSIX: %v): %s", isPOSIX, strings.Join(p, " or "))
2✔
198
        }
2✔
199
        if len(yt.Range) != 0 {
4✔
200
                out += fmt.Sprintf(", Range: %s", yt.Range.String())
2✔
201
        }
2✔
202
        return out + ")"
2✔
203
}
204

205
// SchemaTreeString returns the schema hierarchy tree as a string with node
206
// names and types only e.g.
207
//
208
//            clock (container)
209
//                timezone (choice)
210
//                  timezone-name (case)
211
//                    timezone-name (leaf)
212
//                  timezone-utc-offset (case)
213
//                    timezone-utc-offset (leaf)
214
func SchemaTreeString(schema *yang.Entry, prefix string) string {
2✔
215
        out := prefix + schema.Name + " (" + SchemaTypeStr(schema) + ")" + "\n"
2✔
216
        for _, ch := range schema.Dir {
3✔
217
                out += SchemaTreeString(ch, prefix+"  ")
1✔
218
        }
1✔
219
        return out
2✔
220
}
221

222
// DataSchemaTreesString outputs a combined data/schema tree string where schema
223
// is displayed alongside the data tree e.g.
224
//
225
//        [device (container)]
226
//         RoutingPolicy [routing-policy (container)]
227
//           DefinedSets [defined-sets (container)]
228
//             PrefixSet [prefix-set (list)]
229
//             prefix1
230
//               prefix1
231
//               {255.255.255.0/20 20..24}
232
//                 IpPrefix : "255.255.255.0/20" [ip-prefix (leaf)]
233
//                 MasklengthRange : "20..24" [masklength-range (leaf)]
234
//               PrefixSetName : "prefix1" [prefix-set-name (leaf)]
235
func DataSchemaTreesString(schema *yang.Entry, dataTree interface{}) string {
1✔
236
        printFieldsIterFunc := func(ni *NodeInfo, in, out interface{}) (errs Errors) {
7✔
237
                outs := out.(*string)
6✔
238
                prefix := ""
6✔
239
                for i := 0; i < len(strings.Split(ni.Schema.Path(), "/")); i++ {
18✔
240
                        prefix += "  "
12✔
241
                }
12✔
242

243
                fStr := fmt.Sprintf("%s%s", prefix, ni.StructField.Name)
6✔
244
                schemaStr := fmt.Sprintf("[%s (%s)]", ni.Schema.Name, SchemaTypeStr(ni.Schema))
6✔
245
                switch {
6✔
246
                case IsValueScalar(ni.FieldValue):
2✔
247
                        *outs += fmt.Sprintf("  %s : %s %s\n", fStr, pretty.Sprint(ni.FieldValue.Interface()), schemaStr)
2✔
248
                case !IsNilOrInvalidValue(ni.FieldKey):
1✔
249
                        *outs += fmt.Sprintf("%s%v\n", prefix, ni.FieldKey)
1✔
250
                case !IsNilOrInvalidValue(ni.FieldValue):
2✔
251
                        *outs += fmt.Sprintf("%s %s\n", fStr, schemaStr)
2✔
252
                }
253
                return
6✔
254
        }
255
        var outStr string
1✔
256
        errs := ForEachField(schema, dataTree, nil, &outStr, printFieldsIterFunc)
1✔
257
        if errs != nil {
1✔
258
                outStr = errs.String()
×
259
        }
×
260

261
        return outStr
1✔
262
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc