master
go 136 lines 2.94 KB
Raw
1 // Package common hosts shared helpers for WebSphere framework modules.
2 // SPDX-License-Identifier: GPL-3.0-or-later
3
4 package common
5
6 import (
7 "fmt"
8 "regexp"
9 "strings"
10 )
11
12 // Identity captures the standard WebSphere identification labels.
13 type Identity struct {
14 Cluster string
15 Cell string
16 Node string
17 Server string
18 Edition string
19 Version string
20 }
21
22 // Merge applies non-empty values from src onto dst.
23 func (i *Identity) Merge(src Identity) {
24 if src.Cluster != "" {
25 i.Cluster = src.Cluster
26 }
27 if src.Cell != "" {
28 i.Cell = src.Cell
29 }
30 if src.Node != "" {
31 i.Node = src.Node
32 }
33 if src.Server != "" {
34 i.Server = src.Server
35 }
36 if src.Edition != "" {
37 i.Edition = src.Edition
38 }
39 if src.Version != "" {
40 i.Version = src.Version
41 }
42 }
43
44 // Labels converts the identity into key-value pairs suitable for framework charts.
45 func (i Identity) Labels() map[string]string {
46 labels := make(map[string]string, 6)
47 if i.Cluster != "" {
48 labels["cluster"] = i.Cluster
49 }
50 if i.Cell != "" {
51 labels["cell"] = i.Cell
52 }
53 if i.Node != "" {
54 labels["node"] = i.Node
55 }
56 if i.Server != "" {
57 labels["server"] = i.Server
58 }
59 if i.Edition != "" {
60 labels["websphere_edition"] = i.Edition
61 }
62 if i.Version != "" {
63 labels["websphere_version"] = i.Version
64 }
65 return labels
66 }
67
68 var invalidNameChars = regexp.MustCompile(`[^A-Za-z0-9_]+`)
69
70 // NormaliseName converts arbitrary strings into safe chart/instance identifiers.
71 func NormaliseName(s string) string {
72 s = strings.TrimSpace(s)
73 if s == "" {
74 return "unknown"
75 }
76 s = strings.ReplaceAll(s, " ", "_")
77 s = invalidNameChars.ReplaceAllString(s, "_")
78 s = strings.Trim(s, "_")
79 if s == "" {
80 return "unknown"
81 }
82 return strings.ToLower(s)
83 }
84
85 // InstanceKey builds a stable key prefix for dynamic instances.
86 func InstanceKey(parts ...string) string {
87 cleaned := make([]string, 0, len(parts))
88 for _, part := range parts {
89 if part == "" {
90 continue
91 }
92 cleaned = append(cleaned, NormaliseName(part))
93 }
94 if len(cleaned) == 0 {
95 return "instance_unknown"
96 }
97 return strings.Join(cleaned, ".")
98 }
99
100 // FormatPercent applies the framework precision (value * 1000).
101 func FormatPercent(value float64) int64 {
102 return int64(value * 1000)
103 }
104
105 // FormatRate transforms a per-second float into fixed precision integer.
106 func FormatRate(value float64) int64 {
107 return int64(value * 1000)
108 }
109
110 // FormatBytes returns value as bytes (already integer) for completeness.
111 func FormatBytes(value float64) int64 {
112 return int64(value)
113 }
114
115 // BuildMetricName concatenates segments with underscores.
116 func BuildMetricName(parts ...string) string {
117 cleaned := make([]string, 0, len(parts))
118 for _, p := range parts {
119 if p == "" {
120 continue
121 }
122 cleaned = append(cleaned, NormaliseName(p))
123 }
124 if len(cleaned) == 0 {
125 return "metric"
126 }
127 return strings.Join(cleaned, ".")
128 }
129
130 // CombineErrorContext formats nested error contexts for logging.
131 func CombineErrorContext(ctx, msg string) string {
132 if ctx == "" {
133 return msg
134 }
135 return fmt.Sprintf("%s: %s", ctx, msg)
136 }