web-dev-qa-db-fra.com

Sortie console Jenkins pas en temps réel

Assez nouveau pour Jenkins et j'ai un problème simple mais ennuyeux. Lorsque j'exécute job (Build) sur Jenkins, je déclenche la commande Ruby pour exécuter mon script de test.

Le problème est que Jenkins n'affiche pas la sortie en temps réel de la console. Voici le journal des déclencheurs.

Building in workspace /var/lib/jenkins/workspace/foo_bar
No emails were triggered.
[foo_bar] $ /bin/sh -xe /tmp/hudson4042436272524123595.sh
+ Ruby /var/lib/jenkins/test-script.rb

Fondamentalement, il se bloque sur cette sortie jusqu'à ce que la génération soit terminée qu'il ne montre simplement la sortie complète. Ce qui est drôle, c'est que ce n'est pas un comportement cohérent, parfois cela fonctionne comme il se doit. Mais la plupart du temps, il n'y a pas de sortie de console en temps réel.

Version Jenkins: 1.461

35
Haris Krajina

Pour clarifier certaines des réponses.

  • Ruby ou python ou tout autre langage de script sensible tamponnera la sortie; ceci afin de minimiser les E/S; l'écriture sur le disque est lente, l'écriture sur une console est lente ...
  • habituellement, les données sont flush() 'éditées automatiquement lorsque vous avez suffisamment de données dans le tampon avec une gestion spéciale pour les retours à la ligne. par exemple. écrire une chaîne sans retour à la ligne alors sleep() n'écrirait rien tant que la sleep() n'est pas terminée (j'utilise uniquement sleep comme exemple, n'hésitez pas à remplacer par tout autre appel système coûteux).

par exemple. cela attendre 8 secondes, imprimer une ligne, attendre 5 secondes de plus, imprimer une deuxième ligne.

from time import sleep

def test():
    print "ok",
    time.sleep(3)
    print "now",
    time.sleep(5)
    print "done"
    time.sleep(5)
    print "again"

test()
  • pour Ruby, STDOUT.sync = true , active le autoflush; toutes les écritures dans STDOUT sont suivies de flush(). Cela résoudrait votre problème mais entraînerait davantage d'E/S.

    STDOUT.sync = true
    
  • pour python, vous pouvez utiliser python -u ou la variable d'environnement PYTHONUNBUFFERED pour que stdin/stdout/stout ne soit pas mis en mémoire tampon, mais il existe d'autres solutions qui ne changent pas stdin ou stderr

    export PYTHONUNBUFFERED=1
    
  • pour Perl, vous avez autoflush

    autoflush STDOUT 1;
    
53
dnozay

Assurez-vous que votre script le vide stdout, stderr. Dans mon cas, j'ai eu un problème de polissage similaire à ce que vous décrivez, mais j'utilisais python. Le code python suivant l'a corrigé pour moi:

import sys
sys.stdout.flush()

Je ne suis pas un code Ruby mais Google révèle ce qui suit:

$stdout.flush
10
Craig

Il me semble que python -u fonctionne aussi.

Par exemple. Commande en lot

python -u foo.py
5
Alan Wang

La solution la plus simple consiste à activer la synchronisation du tampon sur la sortie. Quelque chose sur lequel @Craig a écrit dans sa réponse, mais une solution en ligne qui couvrira tout le script et ne vous obligera pas à vider le tampon plusieurs fois.

Ecrivez

STDOUT.sync = true

La logique derrière est simple, pour éviter d'utiliser IO opérations plusieurs fois la sortie est mise en mémoire tampon. Pour désactiver cette utilisation

STDOUT.sync = false

C'est Ruby solution ofc.

4
Haris Krajina

Chacune des autres réponses est spécifique à un programme ou à un autre, mais j'ai trouvé une solution plus générale ici:

https://unix.stackexchange.com/a/25378

Vous pouvez utiliser stdbuf pour modifier le comportement de mise en mémoire tampon de n'importe quel programme.

Dans mon cas, je canalisais la sortie d'un script Shell via tee et grep pour diviser les lignes en console ou en fichier basé sur le contenu. La console était suspendue comme décrit par OP. Cela l'a résolu:

./slowly_parse.py login.csv |tee >(grep -v LOG: > out.csv) | stdbuf -oL -eL grep LOG:

Finalement, j'ai découvert que je pouvais simplement passer --line-buffered à grep pour le même résultat:

./slowly_parse.py login.csv |tee >(grep -v LOG: > out.csv) | grep --line-buffered LOG:
3
dokkaebi

Les autres réponses sont correctes en disant que vous devez vous assurer que la sortie standard n'est pas mise en mémoire tampon.

L'autre chose à savoir est que Jenkins lui-même effectue la mise en mémoire tampon ligne par ligne. Si vous avez un processus lent qui émet des caractères uniques (par exemple, un résumé de la suite de tests d'unité qui imprime un . pour un test réussi et un E pour une erreur) vous ne verrez rien avant la fin de la ligne.

[Vrai pour mon Jenkins 1.572 fonctionnant sur une boîte Windows.]

1
yoyo

Pour certaines commandes, dont tee a, le meilleur choix pour la mise en mémoire tampon est un programme appelé unbuffer à partir de expect package.

Exemple d'utilisation:

au lieu de

somecommand | tee /some/path

faire

somecommand | unbuffer -p tee /some/path

Sources et plus d'informations:

1
Greg Dubicki

Python a mis en mémoire tampon ses traces de sortie et l'affiche à la fin du script pour minimiser l'écriture sur la console car l'écriture sur la console est lente.

Vous pouvez utiliser la commande suivante après vos traces. Il videra toutes les traces sur la console, qui sont mises en file d'attente avant cette commande.

sys.stdout.flush ()

0
Mudassir Hussain

Le système d'exploitation met en mémoire tampon les données de sortie par nature, pour économiser le processeur, tout comme Jenkins.

Il semble que vous utilisiez une commande Shell pour exécuter votre script Ruby -
Je suggère d'exécuter votre script Ruby directement via le plugin dédié:

Jenkins Ruby Plugin

(peut-être besoin de l'installer)

0
Gonen