func populateInstanceHandlers()

in internal/oraclediscovery/oraclediscovery.go [464:555]


func populateInstanceHandlers(ctx context.Context, r io.Reader, listener *odpb.Discovery_Listener) error {
	var (
		currentService    *odpb.Discovery_Listener_Service
		currentInstance   *odpb.Discovery_Listener_Service_DatabaseInstance
		currentHandler    *odpb.Discovery_Listener_Service_DatabaseInstance_Handler
		currentDispatcher *odpb.Discovery_Listener_Service_DatabaseInstance_Handler_Dispatcher
	)

	scanner := bufio.NewScanner(r)

	reService := regexp.MustCompile(`Service\s+"([^"]+)"\s+has\s+\d+\s+instance\(s\)`)
	reInstance := regexp.MustCompile(`Instance\s+"([^"]+)",\s+status\s+(\w+)`)
	reHandler := regexp.MustCompile(`"([^"]+)"\s+established:(\d+)\s+refused:(\d+)(\s+current:(\d+))?(\s+max:(\d+))?\s+state:(\w+)`)
	reDispatcher := regexp.MustCompile(`DISPATCHER\s+<machine:\s+([^,]+),\s+pid:\s+(\d+)>`)
	reAddress := regexp.MustCompile(`\(ADDRESS=\(PROTOCOL=(ipc|tcp|tcps|nmp)\)(\(HOST=([^)]+)\))?(\(PORT=(\d+)\))?(\(SERVER=([^)]+)\))?(\(PIPE=([^)]+)\))?(\(KEY=([^)]+)\))?\)`)

	findServiceByName := func(name string) *odpb.Discovery_Listener_Service {
		for _, service := range listener.Services {
			if service.Name == name {
				return service
			}
		}
		return nil
	}

	findInstanceByName := func(service *odpb.Discovery_Listener_Service, name string) *odpb.Discovery_Listener_Service_DatabaseInstance {
		for _, instance := range service.Instances {
			if instance.Name == name {
				return instance
			}
		}
		return nil
	}

	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())

		switch {
		case reService.MatchString(line):
			serviceName := reService.FindStringSubmatch(line)[1]
			currentService = findServiceByName(serviceName)
		case reInstance.MatchString(line) && currentService != nil:
			instanceName := reInstance.FindStringSubmatch(line)[1]
			currentInstance = findInstanceByName(currentService, instanceName)
		case reHandler.MatchString(line) && currentInstance != nil:
			matches := reHandler.FindStringSubmatch(line)
			name := matches[1]
			state := matches[8]
			currentHandler = &odpb.Discovery_Listener_Service_DatabaseInstance_Handler{
				Name:  name,
				State: parseHandlerState(state), // TODO: Integrate this into the metrics collection pipeline
			}
			if name == "DEDICATED" {
				currentHandler.Type = &odpb.Discovery_Listener_Service_DatabaseInstance_Handler_DedicatedServer_{
					DedicatedServer: &odpb.Discovery_Listener_Service_DatabaseInstance_Handler_DedicatedServer{},
				}
			}
			currentInstance.Handlers = append(currentInstance.Handlers, currentHandler)
		case reDispatcher.MatchString(line) && currentHandler != nil:
			matches := reDispatcher.FindStringSubmatch(line)
			machineName := matches[1]
			pid, err := strconv.Atoi(matches[2])
			if err != nil {
				log.CtxLogger(ctx).Warnw("Failed to parse PID", "error", err, "pid_string", matches[2])
			}
			currentDispatcher = &odpb.Discovery_Listener_Service_DatabaseInstance_Handler_Dispatcher{
				MachineName: machineName,
				Pid:         uint32(pid),
			}
			currentHandler.Type = &odpb.Discovery_Listener_Service_DatabaseInstance_Handler_Dispatcher_{
				Dispatcher: currentDispatcher,
			}
		case reAddress.MatchString(line) && currentDispatcher != nil:
			matches := reAddress.FindStringSubmatch(line)
			port, err := strconv.Atoi(matches[5])
			if err != nil {
				log.CtxLogger(ctx).Warnw("Failed to parse port", "error", err, "port_string", matches[5])
			}
			currentDispatcher.Address = &odpb.Discovery_Listener_Service_DatabaseInstance_Handler_Dispatcher_Address{
				Protocol: matches[1],
				Host:     matches[3],
				Port:     uint32(port),
			}
		}
	}

	if err := scanner.Err(); err != nil {
		return err
	}

	return nil
}