Como incorporar dashboards do Kibana

Um pedido frequente de engenheiros frontend como eu é incorporar dashboards existentes de fontes como o Kibana® em uma aplicação web em JavaScript. É uma tarefa que tive que realizar em várias ocasiões, pois queríamos implantar visualizações geradas pelo usuário rapidamente ou permitir que os usuários controlassem uma determinada visualização. Pelo que vemos das perguntas regulares que recebemos da maravilhosa comunidade de desenvolvedores, não estou sozinha.

Ferramentas de visualização de dados, como os dashboards do Kibana, permitem que até mesmo o usuário com menos habilidades de design ou técnicas crie visualizações e protótipos rapidamente e com facilidade sobre os dados do Elasticsearch®. De fato, isso significa que a incorporação de um dashboard em uma aplicação web existente é a parte mais difícil — especialmente se quisermos integrar controles web personalizados para direcionar a visualização dos dados e proporcionar um estilo e experiência consistentes aos usuários.

Neste artigo, mostrarei exemplos de código de como incorporar dashboards do Kibana em um web app usando iframes HTML. Também abordarei a autenticação do Kibana para essas visualizações e como conectar controles personalizados a visualizações incorporadas usando JavaScript.

O que é um iframe?

Ambos os exemplos abordados neste artigo utilizam um iframe para incorporar nosso dashboard. Um iframe, indicado pela tag HTML <iframe>, permite incorporar outra página da web no documento atual. Especificamente, incluiremos o Painel Global de Voos carregado a partir do conjunto de dados de amostra de voos em nossa própria implantação da Elastic® dentro da nossa página.

Ao incorporar outras fontes em seu aplicativo, é importante garantir que se trate de uma fonte de dados confiável à qual os usuários devam ter acesso. Devemos utilizar políticas de segurança de conteúdo apropriadas, restrições com a propriedade `sandbox` e permissões para limitar as ações do conteúdo incorporado. Ao não especificar o atributo`sandbox` em nosso iframe, incluímos todas as restrições por padrão.

O desempenho também é algo a se considerar ao incluir conteúdo de terceiros na sua aplicação. Como os iframes podem consumir mais largura de banda do que outros recursos, usar muitos deles em uma única aplicação pode deixar toda a aplicação mais lenta. Para quem deseja incorporar vários dashboards Kibana em sua aplicação, tente limitar ao máximo o número incluído e realize testes de desempenho da aplicação. Embora seja fácil adicionar componentes e dashboards, como desenvolvedores precisamos garantir que fornecemos os dados que os usuários precisam, e não todos os controles brilhantes que eles desejam. Então, ao escolher entre dashboards e visualizações, trabalhe com os consumidores para identificar o que eles realmente precisam.

Incorporação básica com iframe HTML

O código para incluir o Global Flight Dashboard em sua aplicação web, conforme abordado neste exemplo básico, é facilmente gerado no Kibana através da opção Compartilhar:

diagrama do código incorporado do Kibana

Um trecho de iframe, adicionando as opções relevantes que você selecionou, junto com os filtros atuais, é gerado para você colar no seu HTML:

<iframe src="https://my-deployment:9243/app/dashboards#/view/7adfa750-4c81-11e8-b3d7-01146121b73d?embed=true&_g=(refreshInterval%3A(pause%3A!t%2Cvalue%3A0)%2Ctime%3A(from%3Anow-1y%2Fd%2Cto%3Anow))&show-top-menu=true&show-query-input=true&show-time-filter=true" height="600" width="800"></iframe>

O trecho de código gerado utiliza medidas em pixels para a largura e altura do iframe. O dimensionamento costuma ser um desafio para garantir que o tamanho do iframe reflita o conteúdo exibido. A melhor prática é considerar o dimensionamento do iframe em relação ao ponto de vista, utilizando os atributos de dimensionamento da viewport vw e vh, ou media queries para lidar com diferentes tamanhos de tela, como parte do design responsivo moderno.

Dado o número de configurações disponíveis, pode ser confuso descobrir o que você precisa. As opções permitem configurar o estado do dashboard e os controles visíveis dentro do iframe.

O tipo de URL a ser gerada pode ser uma de duas opções distintas:

  1. Snapshot: uma URL de codificação do estado atual completo do dashboard, o que significa que as mudanças no dashboard não estão presentes na versão incorporada. 
  2. Objeto salvo: use uma URL referenciando o ID do objeto salvo do dashboard, o que significa que quaisquer alterações feitas no dashboard após a geração da URL serão visíveis para os usuários da aplicação JavaScript.

Segundo a experiência do autor, esses painéis estão sujeitos a alterações. Portanto, a opçãoObjeto salvo seria a mais adequada para incorporação, garantindo que as alterações feitas no painel após a geração da URL sejam visíveis.

As configurações Incluir indicam os controles adicionais a serem incluídos na parte superior do dashboard incorporado:

Elementos do dashboard do Kibana
  1. Menu superior: configurações contendo as funções do dashboard, como editar e tela cheia, controladas incluindo show-top-menu=true na URL do Kibana. 
  2. Consulta: a barra de consulta KQL permite filtrar os dados visíveis no dashboard, representados pelo parâmetro de URL show-query-input=true
  3. Filtro de tempo: o seletor de datas para selecionar o intervalo de datas dos dados no dashboard, ativado usando show-time-filter=true dentro da URL. 
  4. Barra de filtros: oculta as configurações para adicionar filtros aos dados, o que requer definir o parâmetro de URL hide-filter-bar como verdadeiro.

Sem usar a URL pública, você será solicitado a fazer login para acessar o dashboard. Neste ponto, a experiência não é totalmente integrada, mas o dashboard está acessível para quem possui credenciais de login.

Dashboard incorporado sem autenticação anônima

Login automático

Para garantir que o dashboard seja exibido automaticamente, a autenticação precisa ser integrada ao dashboard no Kibana, eliminando a necessidade de os usuários inserirem suas credenciais tanto no aplicativo JavaScript quanto no dashboard. Isso proporciona uma experiência fluida. Isso pode ser feito de duas maneiras:

  1. Habilite a autenticação anônima para fornecer um conjunto padrão de credenciais e permissões para quaisquer solicitações recebidas em que nenhum token de autenticação possa ser extraído (disponível no plano gratuito).

  2. Adiciona compatibilidade para provedor de autenticação de sign-on único SAML para redirecionar usuários não autenticados para o portal de autenticação de sign-on único, e permitir que usuários autenticados acessem o dashboard diretamente. Este é um recurso licenciado.

Aqui, abordaremos a opção de autenticação anônima. Primeiramente, precisamos adicionar um provedor de autenticação anônima anonymous1 ao nosso arquivo kibana.yml:

xpack.security.authc.providers:
  anonymous.anonymous1:
    order: 0
    credentials:
      username: "my_anonymous_user"
      password: "password"

A URL do iframe também deve ser regenerada para especificar o parâmetro auth_provider_hint para vincular as credenciais configuradas para o provedor anonymous1 ao conteúdo incorporado:

<iframe src="https://my-deployment-9f9945.kb.eu-west-2.aws.cloud.es.io:9243/app/dashboards?auth_provider_hint=anonymous1#/view/7adfa750-4c81-11e8-b3d7-01146121b73d?embed=true&_g=(refreshInterval%3A(pause%3A!f%2Cvalue%3A120000)%2Ctime%3A(from%3Anow-1y%2Cto%3Anow))&show-time-filter=true" height="600" width="800"></iframe>

A ausência do parâmetro auth_provider_hint=anonymous1 impedirá o acesso ao dashboard como visitante. Da mesma forma, sem uma função de usuário correspondente registrada no Kibana com o nome do usuário e senha corretos, ocorrerão erros de autenticação:

Autenticação incorporada credencial inválida

Para corrigir isso, certifique-se de ter um usuário registrado com a senha correta, que corresponda à configuração do provedor no seu arquivo kibana.yml. Recomenda-se restringir os privilégios dessa conta ao mínimo necessário, visto que o acesso será concedido a usuários não autenticados.

Kibana Criar Usuário de Autenticação

Neste ponto, você pode pensar que está tudo pronto. No entanto, quando tentar conectar ao seu dashboard, você verá alguns eventos de atualização repetidos e estranhos acontecendo:

Bloco de política de conteúdo incorporado no dashboard

Esse problema ocorre porque o navegador está bloqueando o dashboard do Kibana. Os navegadores modernos aplicam a política de mesma origem para restringir o conteúdo incorporado. Duas URLs compartilham a mesma origem se tiverem o mesmo protocolo, porta e host. Em outras palavras, qualquer conteúdo proveniente de uma origem diferente será bloqueado por padrão, a menos que seja permitido pela política de conteúdo.

Para permitir que o navegador transmita cookies de sessão para o servidor do Kibana em sua pilha ELK com recursos de segurança ativados, que é o padrão a partir do Elastic v8.x, você deve configurar a sameSiteCookies em kibana.yml:

xpack.security.sameSiteCookies: "None"

Com essa etapa final, podemos ver nosso dashboard do Kibana incorporado em nosso aplicativo JavaScript:

dashboard do Kibana básico incorporado

Utilizando controles personalizados

Você deve ter notado que este dashboard utiliza controles para filtrar os dados. É importante permitir que os usuários investiguem os dados e refinem sua seleção para encontrar insights.

Em certas situações, usar os controles do dashboard pode não ser a decisão certa. Você pode querer usar seus próprios controles personalizados para coesão de design dentro de uma aplicação existente. Alternativamente, posicione o dashboard ao lado de fontes de dados adicionais e visualizações que você queira filtrar para formar uma experiência coesa.

Neste exemplo avançado, mostramos como passar as configurações de intervalo de datas de um seletor de datas e de uma seleção suspensa para o dashboard, forçando uma atualização do dashboard:

Dashboard avançado incorporado do Kibana

Usar controles personalizados significa que precisamos entender a composição da URL do dashboard. Vamos explorar o seguinte exemplo:

https://elastic-deployment-9f9945.kb.eu-west-2.aws.cloud.es.io:9243/app/dashboards?auth_provider_hint=anonymous1#/view/7adfa750-4c81-11e8-b3d7-01146121b73d?embed=true&_g=(filters:!(),refreshInterval:(pause:!f,value:0),time:(from:'${selectedStartDate}',to:'${selectedEndDate}'))&_a=(query:(language:kuery,query:'${carrierQuery}'))&hide-time-filter=true

Além dos parâmetros discutidos no exemplo básico, precisamos manipular os filtros. Como discutido anteriormente na comunidade, existem dois níveis de filtros no Kibana:

  1. O estado global, denotado pelo _g, representa o estado que transita entre aplicações Kibana individuais. Um exemplo fundamental disso são os filtros fixados, incluindo as datas de início e término selecionadas.

  2. Estado limitado a aplicações individuais, como o dashboard atual. Isso é representado pelo _a parâmetro de URL _a.

Para passar o intervalo de datas de qualquer seletor de datas, o iframe da URL deve ser atualizado com as datas de início e término selecionadas quando um novo intervalo de datas for aplicado ao controle. Inicialmente, definimos esses valores para um intervalo relativo do último ano. Usando o easepick como exemplo, as novas datas são capturadas no eventode seleção registrado na configuração e convertidas para o formato de data ISO necessário antes que o atributosrc do iframe seja atualizado com a nova URL.

let selectedStartDate = 'now-1y';
let selectedEndDate = 'now';

const picker = new easepick.create({
    element: '#datepicker',
    css: [
        'https://cdn.jsdelivr.net/npm/@easepick/bundle@1.2.1/dist/index.css'
    ],
    zIndex: 10,
    firstDay: 0,
    autoApply: false,
    format: 'MMM DD, YYYY @ HH:MM:00',
    plugins: [
        'RangePlugin',
        'TimePlugin'
    ],
    setup(picker) {
        picker.on('select', (e) => {
            const dateFormat = 'YYYY-MM-DDTHH:MM:00.000Z';
            selectedStartDate =  picker.getStartDate().format(dateFormat);
            selectedEndDate =  picker.getEndDate().format(dateFormat);
            
            dashboardUri=getDashboardUri();
            iframe.setAttribute('src', dashboardUri);
        });
     }
});

Em relação à própria URL, o parâmetro de filtro global _gé então atualizado com o intervalo selecionado, como pode ser visto no getDashboardUri() método auxiliar:

function getDashboardUri() {
    return `https://my-deployment-9f9945.kb.eu-west-2.aws.cloud.es.io:9243/app/dashboards?auth_provider_hint=anonymous1#/view/7adfa750-4c81-11e8-b3d7-01146121b73d?embed=true&_g=(filters:!(),refreshInterval:(pause:!f,value:0),time:(from:'${selectedStartDate}',to:'${selectedEndDate}'))&hide-time-filter=true`;
}

Para filtrar campos de dados em controles como listas suspensas, é necessário passar esses valores usando a opção de consulta no _a parâmetro. select HTML como exemplo:

<div class="carrier-select-container">
  <label for="carrier-select">Carrier</label>
  <select name="carrier-select" id="carrier-select" onchange="updateWithCarrier()">
    <option value="ES-Air">ES-Air</option>
    <option value="JetBeats">JetBeats</option>
    <option value="Kibana Airlines">Kibana Airlines</option>
    <option value="Logstash Airways">Logstash Airways</option>
  </select>
</div>

É possível extrair o valor selecionado quando este é alterado através do método "updateWithCarrier()", que está associado ao "onchange". O evento é obtido do controle de seleção no manipulador de eventos:

function updateWithCarrier() {
    const carrierSelect = document.getElementById('carrier-select');
    selectedCarrier = carrierSelect.value || '';

    dashboardUri=getDashboardUri();
    iframe.setAttribute('src', dashboardUri);
}

Observe que ainda estamos usando o auxiliar getDashboardUri(), que precisa ser atualizado para gerar uma consulta KQL a ser passada para a URL do dashboard por meio da query no filtro do aplicativo:

function getDashboardUri() {
  const carrierQuery = rison.encode_object({Carrier : encodeURIComponent(selectedCarrier)});
  return `https://my-deployment-9f9945.kb.eu-west-2.aws.cloud.es.io:9243/app/dashboards?auth_provider_hint=anonymous1#/view/7adfa750-4c81-11e8-b3d7-01146121b73d?embed=true&_g=(filters:!(),refreshInterval:(pause:!f,value:0),time:(from:'${selectedStartDate}',to:'${selectedEndDate}'))&_a=(query:(language:kuery,query:'${carrierQuery}'))&hide-time-filter=true`;
}

O Kibana utiliza Rison e codificação URI, que precisam ser aplicadas à consulta antes da inclusão. Isso é mencionado na definição de carrierQuery acima, onde usamos rison.js juntamente com o escape do valor selecionado usando o método usual encodeURIComponent.

Uma vez configurado, você verá o dashboard atualizar a cada nova seleção. Fique de olho em erros que indiquem Rison malformado como este erro relatado em nossos fóruns, que pode ser difícil de fazer debug.

Observe que as URLs estão sempre sujeitas a alterações e, portanto, você corre o risco de comprometer a funcionalidade com as novas versões de qualquer ferramenta de terceiros que escolher incorporar. Certifique-se de verificar se há alterações incompatíveis em cada versão do Kibana e teste cuidadosamente seu aplicativo para regressões.

Criando mais dashboards no Kibana

Aqui, mergulhamos no mundo dos dashboards Kibana incorporados. Abordamos um exemplo simples usando um único iframe HTML, juntamente com um exemplo mais complexo usando nossos próprios componentes JavaScript para passar parâmetros para o dashboard. Todo o código está disponível neste repositório do GitHub e pode ser facilmente adaptado para usar sua tecnologia web favorita, framework JavaScript ou TypeScript.

Compartilhe quaisquer dúvidas ou problemas que encontrar ao incorporar dashboards em nossos fóruns da comunidade. Estamos sempre felizes em ajudar. Aproveite seus dashboards!