Aikaleiman valmistelu jokaiselle komennon ulostuloriville

Haluan lisätä aikaleiman jokaiselle komennon lähtö riville. Esimerkki:

foo bar baz 

tulee

[2011-12-13 12:20:38] foo [2011-12-13 12:21:32] bar [2011-12-13 12:22:20] baz 

… missä toistaiseksi etuliite on aika, jolloin viiva tulostettiin. Kuinka voin saavuttaa tämän?

Kommentit

vastaus

moreutils sisältää ts, joka tekee tämän melko hienosti:

command | ts "[%Y-%m-%d %H:%M:%S]"

Se eliminoi myös silmukan tarve, jokaiselle lähtö riville asetetaan aikaleima.

$ echo -e "foo\nbar\nbaz" | ts "[%Y-%m-%d %H:%M:%S]" [2011-12-13 22:07:03] foo [2011-12-13 22:07:03] bar [2011-12-13 22:07:03] baz 

Haluatko tietää, milloin palvelin palasi, käynnistitkö uudelleen? Aja vain ping | ts, ongelma ratkaistu: D.

Kommentit

  • Mistä en ole tiennyt tästä ?!?!?! Tämä täydentää häntä-f hämmästyttävän! tail -f /tmp/script.results.txt | ts
  • jos minulla ei ole ’ komentoa ts, mitä minun pitäisi käyttää?
  • Jos se ’ ei toimi, yritä ohjata stderr stdoutiin esim. ssh -v 127.0.0.1 2>&1 | ts
  • Asenna tekemällä sudo apt install moreutils Debianiin ja yum install moreutils Fedora.
  • Mielestäni parametrin -s osoittaminen on hyödyllistä. Koska se näyttää komennon ajon. Pidän henkilökohtaisesti molempien ts ja ts -s käytöstä samanaikaisesti. Näyttää tältä: command | ts -s '(%H:%M:%.S)]' | ts '[%Y-%m-%d %H:%M:%S'. Tämä valmistelee lokirivit seuraavasti: [2018-12-04 08:31:00 (00:26:28.267126)] Hai <3

Vastaa

Ensinnäkin, jos oletat, että nämä aikaleimat edustavat tapahtumaa, pidä mielessä, että koska monet ohjelmat suorittavat linjapuskurointia (jotkut aggressiivisemmin kuin toiset), on tärkeää ajatella tämä niin lähellä aikaa kuin alkuperäisen rivin on tulostettu pikemminkin kuin tapahtuman aikaleiman.

Voit myös tarkistaa, että komennossasi ei ole jo sisäänrakennettua ominaisuutta, joka on tarkoitettu tähän. Esimerkki: ping -D on joissakin ping -versioissa ja tulostaa Unix-aikakaudesta kuluneen ajan ennen kutakin riviä. Jos komento ei kuitenkaan sisällä omaa tapaa, ovat muutamia menetelmiä ja työkaluja, joita voidaan käyttää, muun muassa:

POSIX-kuori

Muista, että koska monet kuoret tallentavat merkkijononsa sisäisesti käskyinä, jos syötteessä on nolla hiiltyä acter (\0), se voi aiheuttaa linjan päättymisen ennenaikaisesti.

command | while IFS= read -r line; do printf "[%s] %s\n" "$(date "+%Y-%m-%d %H:%M:%S")" "$line"; done 

GNU awk

command | gawk "{ print strftime("[%Y-%m-%d %H:%M:%S]"), $0 }" 

Perl

command | perl -pe "use POSIX strftime; print strftime "[%Y-%m-%d %H:%M:%S] ", localtime" 

Python

command | python -c "import sys,time;sys.stdout.write("".join(( " ".join((time.strftime("[%Y-%m-%d %H:%M:%S]", time.localtime()), line)) for line in sys.stdin )))" 

Rubiini

command | ruby -pe "print Time.now.strftime("[%Y-%m-%d %H:%M:%S] ")" 

Kommentit

  • Yksi ongelma on, että monet ohjelmat käynnistyvät vieläkin enemmän puskurointia, kun niiden vakio on putki päätelaitteen sijaan. Joitakin lähtöpuskurointia voidaan lieventää käyttämällä stdbuf -o 0 -toimintoa, mutta jos ohjelma käsittelee lähdepuskurointiaan manuaalisesti, se ei saanut apua ’ (ellei on mahdollisuus poistaa / pienentää lähtöpuskurin kokoa).
  • Pythonissa voit poistaa rivipuskurin käytöstä python -u
  • @Bwmat No. ... for x in sys.stdin iteroi linjojen yli puskuroimatta niitä ensin muistiin.
  • Tee tämä ja saat puskuroinnin … a in 1 1 1: lle 1 1; nukkua 1; kaiku; valmis | python -c ’ Tuo sys, aika; sys.stdout.write (” ” .join ((” ” .join ((aika.strftime (” [% Y-% m-% d% H:% M:% S] ”, time.gmtime ()), rivi)) sys.stdin-riville))) ’

vastaus

rivikohtaisesta delta-mittauksesta , kokeile gnomon .

Se on komentoriviapuohjelma, vähän kuin moreutils ”s ts, aikaleimatietojen lisääminen toisen komennon vakiolähtöön. Hyödyllinen pitkäkestoisissa prosesseissa, joissa pidät historiallisesta tietueesta siitä, mikä kestää niin kauan.

Minkä tahansa kirjoittaminen gnomonille tulee lisää aikaleima kullekin riville, mikä osoittaa kuinka kauan viiva oli puskurin viimeinen rivi – eli kuinka kauan seuraavan rivin ilmestyminen kesti. Oletuksena gnomon näyttää kuluneet sekunnit jokaisen rivin välillä, mutta se on konfiguroitavissa.

gnomon-esittely

Kommentit

  • Näyttää hyvältä vaihtoehdolta ts käytettäessä live-prosesseja. Vaikka ts sopii paremmin muihin kuin vuorovaikutteisiin prosesseihin.

Vastaa

Olisin halunnut kommentoida yllä, mutta en voi, maineellisesti. Joka tapauksessa yllä olevasta Perl-näytteestä voidaan tehdä puskurointi seuraavasti:

command | perl -pe "use POSIX strftime; $|=1; select((select(STDERR), $| = 1)[0]); print strftime "[%Y-%m-%d %H:%M:%S] ", localtime" 

ensimmäinen ”$ |” -puskuri STDOUT. Toinen asettaa stderr: n nykyiseksi oletusulostulokanavaksi ja purkaa sen. Koska select palauttaa alkuperäisen asetuksen $ |, käärimällä selectin Selectin sisälle palautamme myös $ | STDOUT.

Ja kyllä, voit leikata ”n liitä sellaisenaan. Luin sen moniviivalla luettavuuden vuoksi.

Ja jos todella haluat tarkentua (ja Time :: Hires on asennettu):

command | perl -pe "use POSIX strftime; use Time::HiRes gettimeofday; $|=1; select((select(STDERR), $| = 1)[0]); ($s,$ms)=gettimeofday(); $ms=substr(q(000000) . $ms,-6); print strftime "[%Y-%m-%d %H:%M:%S.$ms]", localtime($s)" 

Kommentit

  • Toimii kuin viehätys tarvitsematta asentaa muita kuin vakiopaketteja.

vastaus

Ryanin viesti tarjoaa mielenkiintoisen idean, mutta se epäonnistuu useissa suhteissa. Testattaessa tail -f /var/log/syslog | xargs -L 1 echo $(date +"[%Y-%m-%d %H:%M:%S]") $1 -tunnistusta huomasin, että aikaleima pysyy samana, vaikka stdout tulee myöhemmin erolla sekunneissa. Harkitse tätä tulosta:

[2016-07-14 01:44:25] Jul 14 01:44:32 eagle dhclient[16091]: DHCPREQUEST of 192.168.0.78 on wlan7 to 255.255.255.255 port 67 (xid=0x411b8c21) [2016-07-14 01:44:25] Jul 14 01:44:34 eagle avahi-daemon[740]: Joining mDNS multicast group on interface wlan7.IPv6 with address fe80::d253:49ff:fe3d:53fd. [2016-07-14 01:44:25] Jul 14 01:44:34 eagle avahi-daemon[740]: New relevant interface wlan7.IPv6 for mDNS. 

Ehdotettu ratkaisuni on samanlainen, mutta tarjoaa oikean aikaleiman ja käyttää hieman kannettavampaa printf eikä echo

| xargs -L 1 bash -c "printf "[%s] %s\n" "$(date +%Y-%m-%d\ %H:%M:%S )" "$*" " bash 

Miksi bash -c "..." bash? Koska -c -vaihtoehdon vuoksi argumentoi ensin nt saa osoitteen $0 ja sitä ei näytetä tulosteessa. Katso shellisi käsikirjasta kuvaus -c

Tämän ratkaisun testaamisesta tail -f /var/log/syslog ja (as luultavasti arvata) katkaisu ja yhteyden muodostaminen wifi-verkkoon on osoittanut sekä date – että syslog -viestien

Bash voidaan korvata millä tahansa bourne-tyyppisellä kuorella, se voidaan tehdä joko ksh tai dash, ainakin niillä joilla on vaihtoehto -c.

Mahdolliset ongelmat:

Ratkaisu vaatii xargs, joka on käytettävissä POSIX-yhteensopivissa järjestelmissä, joten useimmat Unix-tyyppiset järjestelmät tulisi kattaa. Ilmeisesti se ei toimi, jos järjestelmäsi ei ole POSIX-yhteensopiva tai jos sillä ei ole GNU findutils

vastaus

Suurin osa vastauksista ehdottaa date käyttöä, mutta se on tarpeeksi hidasta . Jos bash-versiosi on suurempi kuin 4.2.0, on parempi käyttää sen sijaan printf, se on sisäänrakennettu bash. Jos haluat tukea vanhoja bash-versioita, voit luoda log -toiminnon riippuen bash-versiosta:

TIMESTAMP_FORMAT="%Y-%m-%dT%H:%M:%S" # Bash version in numbers like 4003046, where 4 is major version, 003 is minor, 046 is subminor. printf -v BV "%d%03d%03d" ${BASH_VERSINFO[0]} ${BASH_VERSINFO[1]} ${BASH_VERSINFO[2]} if ((BV > 4002000)); then log() { ## Fast (builtin) but sec is min sample for most implementations printf "%(${TIMESTAMP_FORMAT})T %5d %s\n" "-1" $$ "$*" # %b convert escapes, %s print as is } else log() { ## Slow (subshell, date) but support nanoseconds and legacy bash versions echo "$(date +"${TIMESTAMP_FORMAT}") $$ $*" } fi 

Katso nopeus erot:

user@host:~$time for i in {1..10000}; do printf "%(${TIMESTAMP_FORMAT})T %s\n" "-1" "Some text" >/dev/null; done real 0m0.410s user 0m0.272s sys 0m0.096s user@host:~$time for i in {1..10000}; do echo "$(date +"${TIMESTAMP_FORMAT}") Some text" >/dev/null; done real 0m27.377s user 0m1.404s sys 0m5.432s 

UPD: $(date +"${TIMESTAMP_FORMAT}") sijaan on parempi käyttää $(exec date +"${TIMESTAMP_FORMAT}") tai jopa $(exec -c date +"${TIMESTAMP_FORMAT}") liian nopeutettu suoritus.

UPD2: bash 5 tarjoaa muuttujan EPOCHREALTIME mikrosekunnille tarkkuudella, voit käyttää sitä tällä komennolla (vain noin 30% hitaampaa kuin sekunnit): printf "%(${TIMESTAMP_FORMAT})T.%s %5d %s\n" ${EPOCHREALTIME/./ } $$ "$*"

Kommentit

  • Tämä vastaus on hyvin aliarvioitu! Erityisen mukava näyttää suhteellinen suorituskyky.
  • Erinomainen ehdotus, mutta valitettavasti päivämäärä ei tarjoa sekunnin erottelukykyä, mikä on vaatimus minun tapauksessani
  • Bash 5.0+ -käyttöjärjestelmässä voit käyttää tätä komentoa: printf "%(${TIMESTAMP_FORMAT})T.%s %5d %s\n" ${EPOCHREALTIME/./ } $$ "$*"

Vastaa

Voit tehdä tämän valitsemalla date ja xargs:

... | xargs -L 1 echo `date +"[%Y-%m-%d %H:%M:%S]"` $1 

Selitys:

xargs -L 1 käskee xargs: n suorittamaan etenemiskomennon jokaiselle syötetylle riville, ja se kulkee samalla tavalla ensimmäisellä rivillä. echo `date +"[%Y-%m-%d %H:%M:%S]"` $1 toistaa periaatteessa päivämäärän sen lopussa olevalla syöteargumentilla

Kommentit

  • Ratkaisu on lähellä, mutta ei ’ t aikaleimaa kunnolla, kun kyseessä on pitkällä aikavälillä erotettu lähtö. Lisäksi ’ käytät backtickeja ja haven ’ et noteerannut $1. Se ’ ei ole hyvä tyyli. Lainaa aina muuttujat. Lisäksi ’ käytät echo, joka ei ole kannettava. ’ on kunnossa, mutta se ei välttämättä toimi kunnolla joissakin järjestelmissä.
  • Tämän testaamisen jälkeen näyttää siltä, että olet ’ aivan oikeassa … tiedätkö mitään tapaa tehdä date arvioida jokainen rivi uudelleen, vai onko se melko toivoton?

Vastaa

Häpeämätön pistoke jolle I kirjoitti juuri tämän ongelman ratkaisemiseksi: ets , kirjoitettu Go-muodossa.

esittely

Löydät paljon käyttöesimerkkejä projektisivulta.

Huomattava ero olemassa oleviin vastauksiin ja vastaaviin tarjouksiin on se, että ets on suunniteltu suorittamaan komento puolestasi pty (pseudo tty) – eli simuloimalla komentosi suoritetaan luonnollisesti kymmenessä vuodessa. Verrattuna komentojen ulostulon ohjaamiseen esim. ts, tämä tekee aikaleimat suurimmaksi osaksi läpinäkyviksi ja ratkaisee joukon putkistoja:

  • Jotkut ohjelmat puskuroivat aggressiivisesti, kun kirjoitat putkelle, joten ei näy tulosta ja sitten koko joukko lähtöä (joo, voit stdbuf ne, voit jopa kääri stdbuf ja ts aliakseksi / funktioksi, mutta ei olisi parempi, jos asiat toimisivat laatikosta);
  • Jotkut ohjelmat estävät värin ja / tai vuorovaikutteisuuden kirjoitettaessa putkelle;
  • Poistumistila on kadonnut, ellet ota pipefailia käyttöön jne.

Komennot voivat olla suoraan suoritettu ”ed, mikä tarkoittaa, että voit yksinkertaisesti asettaa ets olemassa olevaan komentoriviin, tai ne voivat olla komentokomentoja (kuten yllä olevassa gifissä on esitetty). Tietenkin, jos haluat lähettää lähdön sisään, ets voi tehdä sen myös.

ets tukee samaa aikaleimamoodit usutils ts: absoluuttinen aikamoodi, kuluneen ajan tila ja inkrementaalinen aikamoodi. Se käyttää saner-oletusasetuksia (esim. Monotonista kelloa käytetään aina kuluneisiin / inkrementaalisiin aikaleimoihin) ja sillä on lisätukea mukautetuille aikavyöhykkeille. Siellä ”on yksityiskohtainen vertailu täällä .

Jälleen, https://github.com/zmwangx/ets . Anna sille pyöriä, ilmoita virheistä jne.

Vastaa

Laita tämä lähellä komentosarjosi alkua

# prepend a timestamp to all output exec &> >( ts "%Y-%m-%d.%H%M.%.S " ) 

Tai, jos haluat ylimääräistä luottoa, lähetä lokitiedostoon:

script_name=foobar log_file=$( printf "/tmp/${script_name}-%(%Y-%m-%d)T.%(%H%M%S)T.log" -1 ) echo "note: redirecting output to [${log_file}]" exec &> >( ts "%Y-%m-%d %H:%M:%.S " > ${log_file} ) 

tulostettavaksi sekä konsolille että lokitiedostolle:

script_name=foobar log_file=$( printf "/tmp/${script_name}-%(%Y-%m-%d)T.%(%H%M%S)T.log" -1 ) exec &> >( ts "%Y-%m-%d %H:%M:%.S " | tee ${log_file} ) 

Tämän tekemisen tärkeimmät edut ovat lokien erottaminen kaikesta muusta, ei sekoittamalla komentosarjan rungon piippaamalla tee tai vastaavaan jokaiseen komentoon, eikä sinun tarvitse kirjoittaa mukautettuja lokitoimintoja ja pitää kiinni tavallisesta vanhasta echo.

ts -ohjelma löytyy paketista moreutils, jonka pitäisi olla helposti saatavilla kaikilla kohtuullisilla alueilla järkevä hallintojärjestelmä. 🙂

Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *