timestamping preciso em logging Python
Pergunta
Eu tenho vindo a construir um aplicativo de log de erro recentemente e foi após uma forma de timestamping com precisão os dados recebidos. Quando eu digo que quero dizer com precisão cada timestamp deve ser preciso em relação ao outro (não há necessidade de sincronização para um relógio atômico ou algo parecido).
Eu tenho usado datetime.now () como uma primeira tentativa, mas isso não é perfeito:
>>> for i in range(0,1000):
... datetime.datetime.now()
...
datetime.datetime(2008, 10, 1, 13, 17, 27, 562000)
datetime.datetime(2008, 10, 1, 13, 17, 27, 562000)
datetime.datetime(2008, 10, 1, 13, 17, 27, 562000)
datetime.datetime(2008, 10, 1, 13, 17, 27, 562000)
datetime.datetime(2008, 10, 1, 13, 17, 27, 578000)
datetime.datetime(2008, 10, 1, 13, 17, 27, 578000)
datetime.datetime(2008, 10, 1, 13, 17, 27, 578000)
datetime.datetime(2008, 10, 1, 13, 17, 27, 578000)
datetime.datetime(2008, 10, 1, 13, 17, 27, 578000)
datetime.datetime(2008, 10, 1, 13, 17, 27, 609000)
datetime.datetime(2008, 10, 1, 13, 17, 27, 609000)
datetime.datetime(2008, 10, 1, 13, 17, 27, 609000)
etc.
As mudanças entre relógios para o primeiro segundo de amostras parecido com este:
uSecs difference
562000
578000 16000
609000 31000
625000 16000
640000 15000
656000 16000
687000 31000
703000 16000
718000 15000
750000 32000
765000 15000
781000 16000
796000 15000
828000 32000
843000 15000
859000 16000
890000 31000
906000 16000
921000 15000
937000 16000
968000 31000
984000 16000
Portanto, parece que os dados de temporizador só é atualizada a cada ~ 15-32ms na minha máquina. O problema surge quando passamos a analisar os dados, porque a classificação por algo que não seja a hora e, em seguida, classificar por timestamp novamente pode deixar os dados na ordem errada (em ordem cronológica). Seria bom ter os carimbos de hora precisos a ponto de que qualquer chamada para o gerador de carimbo de tempo dá um timestamp único.
I tinha sido considerar alguns métodos que envolvem usando uma chamada time.clock () adicionada a uma data e hora de partida, mas iria apreciar uma solução que iria funcionar com precisão através de roscas na mesma máquina. Todas as sugestões serão muito gratamente recebidas.
Solução
Você é improvável que se obtenha o controle suficientemente refinada que você pode eliminar completamente a possibilidade de timestamps duplicados - você precisa de resolução menor do que o tempo que leva para gerar um objeto de data e hora. Há um par de outras abordagens que você pode tomar para lidar com isso:
-
lidar com isso. Deixe suas marcas de tempo não-exclusivo como elas são, mas dependem de sorte ser estável de python para lidar com problemas reordenação. Classificando em timestamp início , em seguida, outra coisa vai manter a ordenação timestamp - você apenas tem que ter o cuidado de sempre começar a partir do timestamp lista ordenada de cada vez, ao invés de fazer vários tipos na mesma lista.
-
Anexe o seu próprio valor para impor exclusividade. Por exemplo. incluem um valor inteiro incrementando como parte da chave, ou de acréscimo valor tal apenas se marcas de tempo são diferentes. Por exemplo.
A seguir irá garantir os valores de timestamp únicas:
class TimeStamper(object):
def __init__(self):
self.lock = threading.Lock()
self.prev = None
self.count = 0
def getTimestamp(self):
with self.lock:
ts = str(datetime.now())
if ts == self.prev:
ts +='.%04d' % self.count
self.count += 1
else:
self.prev = ts
self.count = 1
return ts
Para vários processos (em vez de threads), ele fica um pouco mais complicado embora.
Outras dicas
time.clock () só mede o tempo wallclock no Windows. Em outros sistemas, time.clock () realmente mede CPU-time. Nesses sistemas time.time () é mais adequado para o tempo wallclock, e tem como alta resolução de um como Python pode gerenciar - que é tão alto quanto o sistema operacional pode gerenciar; geralmente usando gettimeofday (3) (resolução de microsegundos) ou ftime (3) (milissegundo resolução.) Outras restrições OS realmente fazer a resolução verdadeira muito maior do que isso. datetime.datetime.now () usa time.time (), então time.time () diretamente não será melhor.
Para o registro, se eu usar datetime.datetime.now () em um loop, eu vejo sobre uma segunda resolução 1/10000. De olhar para os seus dados, você tem muito, resolução grosseira muito do que isso. Eu não tenho certeza se há alguma coisa Python, como tal, pode fazer, embora você pode ser capaz de convencer o OS para fazer melhor através de outros meios.
Se bem me lembro que no Windows, time.clock () é na verdade (ligeiramente) mais preciso do que time.time (), mas ele mede wallclock desde a primeira chamada para time.clock (), então você tem que lembrar para 'initialize' pela primeira vez.
Obrigado a todos por suas contribuições - todos eles ser muito útil. A resposta de Brian parece mais próximo do que eu finalmente fui com (ou seja, lidar com isso, mas usar um tipo de identificador único - veja abaixo) para que eu tenha aceitado sua resposta. I conseguiu consolidar todos os vários receptores de dados em um único segmento que é onde o timestamping agora é feito usando meu novo AccurrateTimeStamp classe. O que eu fiz obras, desde que o carimbo de tempo é a primeira coisa a usar o relógio.
consagra como S. Lott, sem um sistema operacional em tempo real, que nunca vai ser absolutamente perfeito. Eu realmente só queria algo que me deixe ver em relação a cada bloco de entrada de dados, quando as coisas estavam sendo recebidos por isso que eu tenho a seguir irá funcionar bem.
Mais uma vez obrigado a todos!
import time
class AccurateTimeStamp():
"""
A simple class to provide a very accurate means of time stamping some data
"""
# Do the class-wide initial time stamp to synchronise calls to
# time.clock() to a single time stamp
initialTimeStamp = time.time()+ time.clock()
def __init__(self):
"""
Constructor for the AccurateTimeStamp class.
This makes a stamp based on the current time which should be more
accurate than anything you can get out of time.time().
NOTE: This time stamp will only work if nothing has called clock() in
this instance of the Python interpreter.
"""
# Get the time since the first of call to time.clock()
offset = time.clock()
# Get the current (accurate) time
currentTime = AccurateTimeStamp.initialTimeStamp+offset
# Split the time into whole seconds and the portion after the fraction
self.accurateSeconds = int(currentTime)
self.accuratePastSecond = currentTime - self.accurateSeconds
def GetAccurateTimeStampString(timestamp):
"""
Function to produce a timestamp of the form "13:48:01.87123" representing
the time stamp 'timestamp'
"""
# Get a struct_time representing the number of whole seconds since the
# epoch that we can use to format the time stamp
wholeSecondsInTimeStamp = time.localtime(timestamp.accurateSeconds)
# Convert the whole seconds and whatever fraction of a second comes after
# into a couple of strings
wholeSecondsString = time.strftime("%H:%M:%S", wholeSecondsInTimeStamp)
fractionAfterSecondString = str(int(timestamp.accuratePastSecond*1000000))
# Return our shiny new accurate time stamp
return wholeSecondsString+"."+fractionAfterSecondString
if __name__ == '__main__':
for i in range(0,500):
timestamp = AccurateTimeStamp()
print GetAccurateTimeStampString(timestamp)
"timestamp deve ser preciso em relação ao outro"
Por tempo? Por que não um número de seqüência? Se é qualquer cliente de aplicação cliente-servidor, a latência da rede faz timestamps tipo de aleatório.
Você está combinando alguma fonte externa de informações? Digamos que um log em outro aplicativo? Mais uma vez, se há uma rede, naqueles tempos não será muito perto.
Se você deve combinar as coisas entre aplicativos separados, considere passando de GUID em torno de modo que ambos os aplicativos registrar o valor GUID. Então você pode ser absolutamente certo de que eles corresponderem, independentemente das diferenças de tempo.
Se você deseja que o relação para ser exatamente certo, talvez seja suficiente para o seu logger para atribuir um número sequencial para cada mensagem na ordem em que foram recebidos.
Aqui é uma discussão sobre a precisão de tempo Python:
Python - time.clock () vs. time.time () - precisão / p>
Alguns anos passados ??desde que a pergunta foi feita e respondida, e isso tem sido tratado, pelo menos para CPython no Windows. Usando o script abaixo em ambos 64 bits Win7 e Windows Server 2008 R2, eu tenho os mesmos resultados:
-
datetime.now()
dá uma resolução de 1ms e um jitter menor que 1ms -
time.clock()
dá uma resolução melhor que 1us e uma instabilidade muito menor do que 1 ms
O script:
import time
import datetime
t1_0 = time.clock()
t2_0 = datetime.datetime.now()
with open('output.csv', 'w') as f:
for i in xrange(100000):
t1 = time.clock()
t2 = datetime.datetime.now()
td1 = t1-t1_0
td2 = (t2-t2_0).total_seconds()
f.write('%.6f,%.6f\n' % (td1, td2))
Os resultados visualizados:
Eu queria agradecer J. gaiola para este último post.
Para o meu trabalho, o tempo "razoável" de eventos em processos e plataformas é essencial. Existem, obviamente, muitos lugares onde as coisas podem ir torto (desvio de relógio, troca de contexto, etc.), no entanto esta solução timing exacto vai, penso eu, ajudar a garantir que os carimbos de hora gravadas são suficientemente precisos para ver as outras fontes de erro .
Dito isto, há um par de detalhes Eu me pergunto sobre o que são explicados em Quando microssegundos Matéria . Por exemplo, eu acho que time.clock () acabará por quebrar. Eu acho que para que isso funcione para um processo de longa duração, você pode ter que lidar com isso.
Se você quiser microsecond- Resolução (NÃO precisão) timestamps em Python, em Windows, você pode usar temporizador QPC do Windows, conforme demonstrado na minha resposta aqui: Como timestamps microssegundo de resolução de obter milissegundos e em Python . Eu não sei como fazer isso no Linux ainda, então se alguém souber, por favor, comentário ou resposta no link acima.