<commit_before>/*
 * Copyright 2014-2019 the original author or authors.
 *
 * Licensed 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.
 */

import axios, {redirectOn401} from '@/utils/axios';
import waitForPolyfill from '@/utils/eventsource-polyfill';
import logtail from '@/utils/logtail';
import {concat, from, ignoreElements, Observable} from '@/utils/rxjs';
import uri from '@/utils/uri';
import saveAs from 'file-saver';

const actuatorMimeTypes = [
  'application/vnd.spring-boot.actuator.v2+json',
  'application/vnd.spring-boot.actuator.v1+json',
  'application/json'
].join(',');

const isInstanceActuatorRequest = url => url.match(/^instances[/][^/]+[/]actuator([/].*)?$/);

class Instance {
  constructor({id, ...instance}) {
    Object.assign(this, instance);
    this.id = id;
    this.axios = axios.create({
      baseURL: uri`instances/${this.id}/`,
      headers: {'Accept': actuatorMimeTypes}
    });
    this.axios.interceptors.response.use(
      response => response,
      redirectOn401(error => !isInstanceActuatorRequest(error.config.url))
    );
  }

  hasEndpoint(endpointId) {
    return this.endpoints.findIndex(endpoint => endpoint.id === endpointId) >= 0;
  }

  get isUnregisterable() {
    return this.registration.source === 'http-api';
  }

  async unregister() {
    return this.axios.delete('', {
      headers: {'Accept': 'application/json'}
    });
  }

  async fetchInfo() {
    return this.axios.get(uri`actuator/info`);
  }

  async fetchMetrics() {
    return this.axios.get(uri`actuator/metrics`);
  }

  async fetchMetric(metric, tags) {
    const params = tags ? {
      tag: Object.entries(tags)
        .filter(([, value]) => typeof value !== 'undefined' && value !== null)
        .map(([name, value]) => `${name}:${value}`)
        .join(',')
    } : {};
    return this.axios.get(uri`actuator/metrics/${metric}`, {
      params
    });
  }

  async fetchHealth() {
    return await this.axios.get(uri`actuator/health`, {
      validateStatus: null
    });
  }

  async fetchEnv(name) {
    return this.axios.get(uri`actuator/env/${name || ''}`);
  }

  async fetchConfigprops() {
    return this.axios.get(uri`actuator/configprops`);
  }

  async hasEnvManagerSupport() {
    const response = await this.axios.options(uri`actuator/env`);
    return response.headers['allow'] && response.headers['allow'].includes('POST');
  }

  async resetEnv() {
    return this.axios.delete(uri`actuator/env`);
  }

  async setEnv(name, value) {
    return this.axios.post(uri`actuator/env`, {name, value}, {
      headers: {'Content-Type': 'application/json'}
    });
  }

  async refreshContext() {
    return this.axios.post(uri`actuator/refresh`);
  }

  async fetchLiquibase() {
    return this.axios.get(uri`actuator/liquibase`);
  }

  async fetchScheduledTasks() {
    return this.axios.get(uri`actuator/scheduledtasks`);
  }

  async fetchGatewayGlobalFilters() {
    return this.axios.get(uri`actuator/gateway/globalfilters`);
  }

  async addGatewayRoute(route) {
    return this.axios.post(uri`actuator/gateway/routes/${route.id}`, route, {
      headers: {'Content-Type': 'application/json'}
    });
  }

  async fetchGatewayRoutes() {
    return this.axios.get(uri`actuator/gateway/routes`);
  }

  async deleteGatewayRoute(routeId) {
    return this.axios.delete(uri`actuator/gateway/routes/${routeId}`);
  }

  async refreshGatewayRoutesCache() {
    return this.axios.post(uri`actuator/gateway/refresh`);
  }

  async fetchCaches() {
    return this.axios.get(uri`actuator/caches`);
  }

  async clearCaches() {
    return this.axios.delete(uri`actuator/caches`);
  }

  async clearCache(name, cacheManager) {
    return this.axios.delete(uri`actuator/caches/${name}`, {
      params: {'cacheManager': cacheManager}
    });
  }

  async fetchFlyway() {
    return this.axios.get(uri`actuator/flyway`);
  }

  async fetchLoggers() {
    return this.axios.get(uri`actuator/loggers`);
  }

  async configureLogger(name, level) {
    await this.axios.post(uri`actuator/loggers/${name}`, {configuredLevel: level}, {
      headers: {'Content-Type': 'application/json'}
    });
  }

  async fetchHttptrace() {
    return this.axios.get(uri`actuator/httptrace`);
  }

  async fetchBeans() {
    return this.axios.get(uri`actuator/beans`);
  }

  async fetchThreaddump() {
    return this.axios.get(uri`actuator/threaddump`);
  }

  async downloadThreaddump() {
    const res = await axios.get(uri`actuator/threaddump`, {headers: {'Accept': 'text/plain'}});
    const blob = new Blob([res.data], {type: 'text/plain;charset=utf-8'});
    saveAs(blob, this.registration.name + '-threaddump.txt');<commit_msg>Fix for downloading ThreadDump file<commit_after>/*
 * Copyright 2014-2019 the original author or authors.
 *
 * Licensed 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.
 */

import axios, {redirectOn401} from '@/utils/axios';
import waitForPolyfill from '@/utils/eventsource-polyfill';
import logtail from '@/utils/logtail';
import {concat, from, ignoreElements, Observable} from '@/utils/rxjs';
import uri from '@/utils/uri';
import saveAs from 'file-saver';

const actuatorMimeTypes = [
  'application/vnd.spring-boot.actuator.v2+json',
  'application/vnd.spring-boot.actuator.v1+json',
  'application/json'
].join(',');

const isInstanceActuatorRequest = url => url.match(/^instances[/][^/]+[/]actuator([/].*)?$/);

class Instance {
  constructor({id, ...instance}) {
    Object.assign(this, instance);
    this.id = id;
    this.axios = axios.create({
      baseURL: uri`instances/${this.id}/`,
      headers: {'Accept': actuatorMimeTypes}
    });
    this.axios.interceptors.response.use(
      response => response,
      redirectOn401(error => !isInstanceActuatorRequest(error.config.url))
    );
  }

  hasEndpoint(endpointId) {
    return this.endpoints.findIndex(endpoint => endpoint.id === endpointId) >= 0;
  }

  get isUnregisterable() {
    return this.registration.source === 'http-api';
  }

  async unregister() {
    return this.axios.delete('', {
      headers: {'Accept': 'application/json'}
    });
  }

  async fetchInfo() {
    return this.axios.get(uri`actuator/info`);
  }

  async fetchMetrics() {
    return this.axios.get(uri`actuator/metrics`);
  }

  async fetchMetric(metric, tags) {
    const params = tags ? {
      tag: Object.entries(tags)
        .filter(([, value]) => typeof value !== 'undefined' && value !== null)
        .map(([name, value]) => `${name}:${value}`)
        .join(',')
    } : {};
    return this.axios.get(uri`actuator/metrics/${metric}`, {
      params
    });
  }

  async fetchHealth() {
    return await this.axios.get(uri`actuator/health`, {
      validateStatus: null
    });
  }

  async fetchEnv(name) {
    return this.axios.get(uri`actuator/env/${name || ''}`);
  }

  async fetchConfigprops() {
    return this.axios.get(uri`actuator/configprops`);
  }

  async hasEnvManagerSupport() {
    const response = await this.axios.options(uri`actuator/env`);
    return response.headers['allow'] && response.headers['allow'].includes('POST');
  }

  async resetEnv() {
    return this.axios.delete(uri`actuator/env`);
  }

  async setEnv(name, value) {
    return this.axios.post(uri`actuator/env`, {name, value}, {
      headers: {'Content-Type': 'application/json'}
    });
  }

  async refreshContext() {
    return this.axios.post(uri`actuator/refresh`);
  }

  async fetchLiquibase() {
    return this.axios.get(uri`actuator/liquibase`);
  }

  async fetchScheduledTasks() {
    return this.axios.get(uri`actuator/scheduledtasks`);
  }

  async fetchGatewayGlobalFilters() {
    return this.axios.get(uri`actuator/gateway/globalfilters`);
  }

  async addGatewayRoute(route) {
    return this.axios.post(uri`actuator/gateway/routes/${route.id}`, route, {
      headers: {'Content-Type': 'application/json'}
    });
  }

  async fetchGatewayRoutes() {
    return this.axios.get(uri`actuator/gateway/routes`);
  }

  async deleteGatewayRoute(routeId) {
    return this.axios.delete(uri`actuator/gateway/routes/${routeId}`);
  }

  async refreshGatewayRoutesCache() {
    return this.axios.post(uri`actuator/gateway/refresh`);
  }

  async fetchCaches() {
    return this.axios.get(uri`actuator/caches`);
  }

  async clearCaches() {
    return this.axios.delete(uri`actuator/caches`);
  }

  async clearCache(name, cacheManager) {
    return this.axios.delete(uri`actuator/caches/${name}`, {
      params: {'cacheManager': cacheManager}
    });
  }

  async fetchFlyway() {
    return this.axios.get(uri`actuator/flyway`);
  }

  async fetchLoggers() {
    return this.axios.get(uri`actuator/loggers`);
  }

  async configureLogger(name, level) {
    await this.axios.post(uri`actuator/loggers/${name}`, {configuredLevel: level}, {
      headers: {'Content-Type': 'application/json'}
    });
  }

  async fetchHttptrace() {
    return this.axios.get(uri`actuator/httptrace`);
  }

  async fetchBeans() {
    return this.axios.get(uri`actuator/beans`);
  }

  async fetchThreaddump() {
    return this.axios.get(uri`actuator/threaddump`);
  }

  async downloadThreaddump() {
    const res = await this.axios.get(uri`actuator/threaddump`, {headers: {'Accept': 'text/plain'}});
    const blob = new Blob([res.data], {type: 'text/plain;charset=utf-8'});
    saveAs(blob, this.registration.name + '-threaddump.txt');
{'fraction_non_alphanumeric': 0.15634389842008337, 'fraction_numerical': 0.00426480566056024, 'mean_word_length': 3.6561371841155235, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 3, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4247804', 'n_tokens_mistral': 3474, 'n_tokens_neox': 3428, 'n_words': 663}