Не забудьте использовать Arthas для отладки онлайн

Java
Не забудьте использовать Arthas для отладки онлайн

описание проблемы

Обнаружена ошибка в проекте, работающем онлайн. В ходе расследования возникло подозрение, что бин в конфигурационном файле не был успешно прочитан. Обычно мой подход состоит в том, чтобы добавить строку журнала, а затем перестроить код. Например:log.info("WxDomainProperties:{}",wxDomainProperties);

Давайте посмотрим, как выглядят свойства этого объекта.

Но это, очевидно, относительно неэффективный способ. Ниже представлен способ использования arthas с открытым исходным кодом Ali для реализации онлайн-отладки.

Сначала посмотрите на соответствующий код

Bean-компонент, который, как предполагается, имеет проблемы, — это следующий bean-компонент, который в основном используется для настройки информации о доменном имени. Значение, настроенное через файл конфигурации. В разных средах, таких как dev, local, online будут разные значения.

/**
 * 微信第三方平台域名配置
 *
 * @author yanghaolei
 * @date 2019/08/07 下午4:04
 */
@Data
@Component
@ConfigurationProperties(prefix = WxDomainProperties.PREFIX)
public class WxDomainProperties {

    public static final String PREFIX = "wx.domain";

    /**
     * 请求域名
     */
    private List<String> requestDomainList = Lists.newArrayList();

    /**
     * WebSocket域名
     */
    private List<String> wsRequestDomainList = Lists.newArrayList();

    /**
     * 上传域名
     */
    private List<String> uploadDomainList = Lists.newArrayList();

    /**
     * 下载域名
     */
    private List<String> downloadDomainList = Lists.newArrayList();

    /**
     * 业务域名
     */
    private List<String> webviewDomainList = Lists.newArrayList();
}

Затем мы внедряем этот компонент в бизнес-код.

@Slf4j
@AllArgsConstructor
@Service
public class MaDomainService {
    private final WxService wxService;
    private final WxDomainProperties wxDomainProperties;

В методе setDoamin значение, сохраненное компонентом, по умолчанию загружается автоматически. И ошибка, с которой я столкнулся, заключалась в том, что по умолчанию все загруженные значения были нулевыми. Так что я подозреваю, что что-то не так со значениями, которые читает этот конфиг.

 public WxOpenMaDomainResult setDomain(MaDomainSetDTO maDomainSetDTO) {
        JSONObject requestJson = new JSONObject();
        Integer status = maDomainSetDTO.getStatus();
        String appId = maDomainSetDTO.getAppId();

        // 1 启用默认配置 --> 强制覆盖成默认列表[初始化操作]
        if (StatusEnum.TRUE.getValue().equals(status)) {
            requestJson.put("action", SET_ACTION);
            requestJson.put("requestdomain", JSONArray.parse(JSON.toJSONString(wxDomainProperties.getRequestDomainList())));
            requestJson.put("wsrequestdomain", JSONArray.parseArray(JSON.toJSONString(wxDomainProperties.getWsRequestDomainList())));
            requestJson.put("uploaddomain", JSONArray.parseArray(JSON.toJSONString(wxDomainProperties.getUploadDomainList())));
            requestJson.put("downloaddomain", JSONArray.parseArray(JSON.toJSONString(wxDomainProperties.getDownloadDomainList())));
        }
        // 2 未启用默认配置 --> 可以add/delete/get[不允许自定义set]
        else if (StatusEnum.FALSE.getValue().equals(status)) {
            //不允许自定义覆盖
            if (SET_ACTION.equals(maDomainSetDTO.getAction())) {
                return new WxOpenMaDomainResult();
            }
            requestJson.put("requestdomain", getJsonArray(maDomainSetDTO.getRequestDomainList()));
            requestJson.put("wsrequestdomain", getJsonArray(maDomainSetDTO.getWsRequestDomainList()));
            requestJson.put("uploaddomain", getJsonArray(maDomainSetDTO.getUploadDomainList()));
            requestJson.put("downloaddomain", getJsonArray(maDomainSetDTO.getDownloadDomainList()));
        } else {
            return new WxOpenMaDomainResult();
        }

        try {
            String response = wxService.getMaService(appId).post(API_MODIFY_DOMAIN, requestJson.toJSONString());
            return JSON.parseObject(response, WxOpenMaDomainResult.class);
        } catch (Exception e) {
            log.error("Error message:{},Error stackTrace:{}", e.getMessage(), e.getStackTrace());
            return new WxOpenMaDomainResult();
        }
    }

Для того, чтобы убедиться, что с моим подозрением нет проблем, конечно, необходимо отладить, чтобы проверить это значение. Но это онлайн-код, как было сказано в начале, хлопотнее проверить значение, перезапустив лог. Поэтому я подумал об использовании Arthas для онлайн-отладки.

Артас в действии

Большая часть информации в Интернете по знакомству с Arthas посвящена установке и просмотру некоторой информации о консоли. Вот официальный сайт,Начало работы с Артасом. В основном я буду говорить о моем процессе проверки моих сомнений и, наконец, о нахождении причины с помощью артаса.

Здесь я использую команды watch и trace.

Команда watch выполняет наблюдение за данными, что позволяет нам легко наблюдать за вызовом указанного метода. Формат наблюдения: просмотр + совпадение выражения имени класса + имя метода + выражение + условное выражение. Я здесь, чтобы наблюдать, успешно ли значение wxDomainProperties считывается конфигурационным файлом во время вызова метода setDomain. Итак, мое выражение: watch + имя класса [com.bjyt.bange.module.wx.middleware.MaDomainService] + имя метода [setDomain] + выражение ['target.wxDomainProperties']. Здесь target представляет текущий объект. Условные выражения часто используются для указания точек наблюдения и времени наблюдения, поэтому здесь они не заполняются, поскольку не нужны. Вы можете увидеть результат выполнения:

Как видите, мои подозрения неверны, этот боб имеет ценность. Вот почему добавление журналов неэффективно, и потребуется много времени, чтобы проверить неправильное подозрение.

Затем я использовал команду trace, надеясь проследить, как этот метод работает внутри. Команда trace может отслеживать путь вызова внутри метода и выводить время, затрачиваемое на каждый узел пути метода. Разница между ним и стеком заключается в том, что вывод стека является путем вызова текущего метода. Формат трассировки также следующий: трассировка + имя класса + имя метода + выражение. Вот результат выполнения:

Здесь хорошо видно, что исключение выброшено в позиции предпоследней строки. После анализа я обнаружил, что мой код неверен. . . Наконец, по результатам arthas, мы завершили онлайн-отладку.

Напоследок: об использовании arthas в k8s или докере

Arthas должен запустить процесс jvm на текущей машине для работы. В реальной производственной среде все наши онлайн-машины должны быть развернуты в k8s или докере. То есть на эти онлайн-машины тоже нужно установить arthas. Это также специально упоминается в официальном руководстве Али по развертыванию артас в контейнерах.

На самом деле, я думаю, что разработчикам будет лучше установить Arthas локально. Затем подключитесь к Arthas в Docker через веб-консоль Arthas. Затем отлаживайте на удаленной линии через консоль. Это также подтверждается в официальном пользовательском кейсе.Документ, как использовать Arthas для удаленного доступа # 442. Таким образом, можно установить более эффективный режим разработки. И это может значительно уменьшить количество кода регистрации, такого как log.info в коде. Учитывая, что функция артха гораздо шире, следует сказать, что ее все же стоит рассмотреть.