youtubebeat/vendor/github.com/elastic/beats/metricbeat/module/jolokia/jmx/config.go

181 lines
5.7 KiB
Go

// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package jmx
import (
"encoding/json"
"fmt"
"regexp"
"sort"
"strings"
)
type JMXMapping struct {
MBean string
Attributes []Attribute
Target Target
}
type Attribute struct {
Attr string
Field string
Event string
}
// Target inputs the value you want to set for jolokia target block
type Target struct {
URL string
User string
Password string
}
// RequestBlock is used to build the request blocks of the following format:
//
// [
// {
// "type":"read",
// "mbean":"java.lang:type=Runtime",
// "attribute":[
// "Uptime"
// ]
// },
// {
// "type":"read",
// "mbean":"java.lang:type=GarbageCollector,name=ConcurrentMarkSweep",
// "attribute":[
// "CollectionTime",
// "CollectionCount"
// ],
// "target":{
// "url":"service:jmx:rmi:///jndi/rmi://targethost:9999/jmxrmi",
// "user":"jolokia",
// "password":"s!cr!t"
// }
// }
// ]
type RequestBlock struct {
Type string `json:"type"`
MBean string `json:"mbean"`
Attribute []string `json:"attribute"`
Config map[string]interface{} `json:"config"`
Target *TargetBlock `json:"target,omitempty"`
}
// TargetBlock is used to build the target blocks of the following format into RequestBlock.
//
// "target":{
// "url":"service:jmx:rmi:///jndi/rmi://targethost:9999/jmxrmi",
// "user":"jolokia",
// "password":"s!cr!t"
// }
type TargetBlock struct {
URL string `json:"url"`
User string `json:"user,omitempty"`
Password string `json:"password,omitempty"`
}
type attributeMappingKey struct {
mbean, attr string
}
// AttributeMapping contains the mapping information between attributes in Jolokia
// responses and fields in metricbeat events
type AttributeMapping map[attributeMappingKey]Attribute
// Get the mapping options for the attribute of an mbean
func (m AttributeMapping) Get(mbean, attr string) (Attribute, bool) {
a, found := m[attributeMappingKey{mbean, attr}]
return a, found
}
// Parse strings with properties with the format key=value, being:
// - key a nonempty string of characters which may not contain any of the characters,
// comma (,), equals (=), colon, asterisk, or question mark.
// - value a string that can be quoted or unquoted, if unquoted it cannot be empty and
// cannot contain any of the characters comma, equals, colon, or quote.
var propertyRegexp = regexp.MustCompile("[^,=:*?]+=([^,=:\"]+|\".*\")")
func canonicalizeMBeanName(name string) (string, error) {
// From https://docs.oracle.com/javase/8/docs/api/javax/management/ObjectName.html#getCanonicalName--
//
// Returns the canonical form of the name; that is, a string representation where the
// properties are sorted in lexical order.
// The canonical form of the name is a String consisting of the domain part,
// a colon (:), the canonical key property list, and a pattern indication.
//
parts := strings.SplitN(name, ":", 2)
if len(parts) != 2 || parts[0] == "" || parts[1] == "" {
return name, fmt.Errorf("domain and properties needed in mbean name: %s", name)
}
domain := parts[0]
// Using this regexp instead of just splitting by commas because values can be quoted
// and contain commas, what complicates the parsing.
properties := propertyRegexp.FindAllString(parts[1], -1)
propertyList := strings.Join(properties, ",")
if len(propertyList) != len(parts[1]) {
// Some property didn't match
return name, fmt.Errorf("mbean properties must be in the form key=value: %s", name)
}
sort.Strings(properties)
return domain + ":" + strings.Join(properties, ","), nil
}
func buildRequestBodyAndMapping(mappings []JMXMapping) ([]byte, AttributeMapping, error) {
responseMapping := make(AttributeMapping)
var blocks []RequestBlock
// At least Jolokia 1.5 responses with canonicalized MBean names when using
// wildcards, even when canonicalNaming is set to false, this makes mappings to fail.
// So use canonicalized names everywhere.
// If Jolokia returns non-canonicalized MBean names, then we'll need to canonicalize
// them or change our approach to mappings.
config := map[string]interface{}{
"ignoreErrors": true,
"canonicalNaming": true,
}
for _, mapping := range mappings {
mbean, err := canonicalizeMBeanName(mapping.MBean)
if err != nil {
return nil, nil, err
}
rb := RequestBlock{
Type: "read",
MBean: mbean,
Config: config,
}
if len(mapping.Target.URL) != 0 {
rb.Target = new(TargetBlock)
rb.Target.URL = mapping.Target.URL
rb.Target.User = mapping.Target.User
rb.Target.Password = mapping.Target.Password
}
for _, attribute := range mapping.Attributes {
rb.Attribute = append(rb.Attribute, attribute.Attr)
responseMapping[attributeMappingKey{mbean, attribute.Attr}] = attribute
}
blocks = append(blocks, rb)
}
content, err := json.Marshal(blocks)
return content, responseMapping, err
}