- 수집할 매트릭 정보와 프로메테우스 Url 정보 입력: Prometheus가 설치되어있는 주소와 포트번호, 수집할 매트릭 정보의 key 값들을 각각의 독립적인 변수에 저장
 
String prometheusUrl = "http://133.186.215.103:9090";
String promQLQueryCpu = "libvirt_domain_info_cpu_time_seconds_total";
String promQLQueryMemory = "libvirt_domain_info_memory_usage_bytes";
String promQLQueryVirtualCpu = "libvirt_domain_info_virtual_cpus";
- 시간 범위 설정: startTime과 endTime를 사용하여 현재 시간으로부터 1시간 전까지의 데이터를 수집하도록 설정
→ 24시간 동안의 데이터를 수집하려면 startTime을 현재 시간에서 24시간 (24 * 3600000 밀리초) 전으로 설정 
long endTime = System.currentTimeMillis(); // 현재 시간
long startTime = endTime - 3600000; // 60분 전 (* N을 통해 수집하고자 하는 시간 늘릴 수 있음)
- PromQL
 
RestTemplate restTemplate = new RestTemplate();
String prometheusQueryURLCpu = prometheusUrl + "/api/v1/query_range?query=" + promQLQueryCpu +
"&start=" + startTime / 1000 + "&end=" + endTime / 1000 + "&step=60"; // step=60은 1분 간격
- /api/v1/query_range: Prometheus API 엔드포인트 중 하나로, 범위를 지정하여 메트릭 데이터를 가져올 수 있다.
 
- promQLQueryCpu: 수집할 메트릭 이름
 
- startTime 및 endTime: startTime과 endTime의 값을 초 단위로 변환하여 URL에 포함
→ 밀리초에서 초 단위로 값을 변경해야하므로, 나누기 1000 
- step=60: 데이터의 간격(step)을 설정
→ 60으로 설정되어 있으므로 1분 간격으로 데이터를 수집 
- HTTP 요청: RestTemplate을 사용하여 Prometheus 서버로 HTTP GET 요청을 보내고, 서버로부터 반환된 응답을 받아온다.
 
ResponseEntity<String> responseCpu = restTemplate.getForEntity(prometheusQueryURLCpu, String.class);
- Status code 확인: HTTP 요청이 성공적으로 처리되었는지 확인하고, getBody()를 사용하여 응답 데이터를 문자열로 추출
 
if (responseCpu.getStatusCode().is2xxSuccessful()) {
	String resultCpu = responseCpu.getBody();
}        
- Parsing
 
 ObjectMapper objectMapper = new ObjectMapper();
            try {
                JsonNode rootNodeCpu = objectMapper.readTree(resultCpu);
                JsonNode dataNodeCpu = rootNodeCpu.get("data");
                JsonNode resultNodeCpu = dataNodeCpu.get("result");
                .
                .
                .
- ObjectMapper는 Jackson 라이브러리의 일부로, JSON 데이터를 Java 객체로 변환
 
- objectMapper.readTree(resultCpu): resultCpu 문자열을 JSON 구조로 파싱
 
- rootNodeCpu.get("data"): JsonNode 객체에서 "data" 필드를 찾아 해당 하위 노드를 반환
 
- dataNodeCpu.get("result"): "data" 하위 노드에서 "result" 필드를 찾아 그 내용을 추출
→ "result" 필드는 실제 메트릭 데이터를 포함하고 있는 노드 
- 완성코드
 
package openstack.eco_stack.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.client.RestTemplate;
import org.springframework.http.ResponseEntity;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.ArrayList;
import java.util.List;
@Slf4j
public class PrometheusDataFetcher {
    public static void main(String[] args) {
        // Prometheus 서버 URL 및 수집할 매트릭 key
        String prometheusUrl = "http://133.186.215.103:9090";
        String promQLQueryCpu = "libvirt_domain_info_cpu_time_seconds_total";
        String promQLQueryMemory = "libvirt_domain_info_memory_usage_bytes";
        String promQLQueryVirtualCpu = "libvirt_domain_info_virtual_cpus";
        long endTime = System.currentTimeMillis(); // 현재 시간
        long startTime = endTime - 3600000; // 60분 전 (* N을 통해 수집하고자 하는 시간 늘릴 수 있음)
        // PromQL
        RestTemplate restTemplate = new RestTemplate();
        String prometheusQueryURLCpu = prometheusUrl + "/api/v1/query_range?query=" + promQLQueryCpu +
                "&start=" + startTime / 1000 + "&end=" + endTime / 1000 + "&step=60"; // step=60은 1분 간격
        String prometheusQueryURLMemory = prometheusUrl + "/api/v1/query_range?query=" + promQLQueryMemory +
                "&start=" + startTime / 1000 + "&end=" + endTime / 1000 + "&step=60"; // step=60은 1분 간격
        String prometheusQueryURLVirtualCpu = prometheusUrl + "/api/v1/query_range?query=" + promQLQueryVirtualCpu +
                "&start=" + startTime / 1000 + "&end=" + endTime / 1000 + "&step=60"; // step=60은 1분 간격
        ResponseEntity<String> responseCpu = restTemplate.getForEntity(prometheusQueryURLCpu, String.class);
        ResponseEntity<String> responseMemory = restTemplate.getForEntity(prometheusQueryURLMemory, String.class);
        ResponseEntity<String> responseVirtualCpu = restTemplate.getForEntity(prometheusQueryURLVirtualCpu, String.class);
        // 결과를 저장할 리스트
        List<String> resultLines = new ArrayList<>();
        // 출력
        if (responseCpu.getStatusCode().is2xxSuccessful() && responseMemory.getStatusCode().is2xxSuccessful() && responseVirtualCpu.getStatusCode().is2xxSuccessful()) {
            String resultCpu = responseCpu.getBody();
            String resultMemory = responseMemory.getBody();
            String resultVirtualCpu = responseVirtualCpu.getBody();
            // JSON 파싱을 위한 ObjectMapper
            ObjectMapper objectMapper = new ObjectMapper();
            try {
                JsonNode rootNodeCpu = objectMapper.readTree(resultCpu);
                JsonNode dataNodeCpu = rootNodeCpu.get("data");
                JsonNode resultNodeCpu = dataNodeCpu.get("result");
                JsonNode rootNodeMemory = objectMapper.readTree(resultMemory);
                JsonNode dataNodeMemory = rootNodeMemory.get("data");
                JsonNode resultNodeMemory = dataNodeMemory.get("result");
                JsonNode rootNodeVirtualCpu = objectMapper.readTree(resultVirtualCpu);
                JsonNode dataNodeVirtualCpu = rootNodeVirtualCpu.get("data");
                JsonNode resultNodeVirtualCpu = dataNodeVirtualCpu.get("result");
                for (int i = 0; i < resultNodeCpu.size(); i++) {
                    // projectId 필드를 가져오기
                    String projectIdCpu = resultNodeCpu.get(i).get("metric").get("projectId").asText();
                    String projectIdMemory = resultNodeMemory.get(i).get("metric").get("projectId").asText();
                    String projectIdVirtualCpu = resultNodeVirtualCpu.get(i).get("metric").get("projectId").asText();
                    StringBuilder message = new StringBuilder();
                    message.append("Project ID: ").append(projectIdCpu).append("\n");
                    JsonNode valuesNodeCpu = resultNodeCpu.get(i).get("values");
                    JsonNode valuesNodeMemory = resultNodeMemory.get(i).get("values");
                    JsonNode valuesNodeVirtualCpu = resultNodeVirtualCpu.get(i).get("values");
                    // CPU TIME 출력
                    message.append("CPU TIME: ");
                    for (JsonNode valueNode : valuesNodeCpu) {
                        double cpuTime = valueNode.get(1).asDouble();
                        message.append(cpuTime).append(", ");
                    }
                    message.append("\n");
                    // VIRTUAL CPU 출력
                    message.append("VIRTUAL CPU: ");
                    for (JsonNode valueNode : valuesNodeVirtualCpu) {
                        double virtualCpu = valueNode.get(1).asDouble();
                        message.append(virtualCpu).append(", ");
                    }
                    message.append("\n");
                    // MEMORY USAGE 출력
                    message.append("MEMORY USAGE: ");
                    for (JsonNode valueNode : valuesNodeMemory) {
                        double memoryUsage = valueNode.get(1).asDouble();
                        message.append(memoryUsage).append(", ");
                    }
                    message.append("\n");
                    resultLines.add(message.toString());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            System.err.println("HTTP 요청 실패: " + responseCpu.getStatusCode() + ", " + responseMemory.getStatusCode() + ", " + responseVirtualCpu.getStatusCode());
        }
        // 결과 출력
        for (String line : resultLines) {
            log.info(line);
        }
    }
}