본문 바로가기
Back-end/Python

[Tail] Python을 이용한 tail --follow 기능 구현

by 허도치 2020. 7. 20.
서론

  최근 PyQt5로 React를 빌드하거나 Webpack Server, 웹 서버를 실행하는 PyQt앱을 구현하였다. 웹 로그를 화면에 출력하기 위해서 [ tail --follow <파일명> ]명령를 사용하였다. 그런데, OSX에서 개발할 때는 문제가 없었지만, Windows에서는 tail 명령이 없기 때문에 오류가 발생했다.

 

  그래서, [ tail --follow <파일명> ] 명령을 Python으로 간단하게 구현해보았다.

 

 

1. 소스 작성
1-1. Class 작성 - tailer.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# tailer.py
import time
 
# Main Class
class Tailer(object):
  def __init__(selffile=None, end=False, lines=0*args, **kwargs):
    self.args = args
    self.kwargs = kwargs
    
    self.isRunning = False
    self.newlines = [ '\n''\r''\r\n' ]
    self.file = file
    
    if end: self.seek_end()
  
  # File 셋팅
  def setFile(selffile):
    self.file = file
  
  # File의 offset 위치 설정
  def seek(self, offset, whence=0):
    self.file.seek(offset, whence)
  
  # File의 offset을 맨 앞으로 이동
  def seek_first(self):
    self.seek(0,1)
  
  # File의 offset을 맨 뒤로 이동  
  def seek_end(self):
    self.seek(0,2)
  
  # Follow
  def follow(self, delay=1.0):
    self.isRunning = True
    
    tailling = True
    
    while self.isRunning:
      # File의 현재 offset 위치
      pivot = self.file.tell()
      
      # File의 현재 offset 위치의 line 가져오기.
      # offset이 변경됨.
      line = self.file.readline()
      
      if line:
        # EOF가 개행문자가 아닌 경우, 다음 문자부터 출력
        if tailling and line in self.newlines:
          tailling = False
          continue
        
        # Line 끝에 개행문자 제거
        if line[-1in self.newlines:
          line = line[:-1]
          if line[-1:] == '\r\n' and '\r\n' in self.newlines:
            line = line[:-1]
        
        tailling = False
        yield line
      
      else:
        tailling = True
        
        # File의 offset을 이전 위치로 변경
        self.file.seek(pivot)
        
        time.sleep(delay)
    
  def stop(self):
    self.isRunning = False
    self.file.close()
 
def follow(file, delay=1.0**kwargs):
  tailer = Tailer(file, end=True**kwargs)
  return ( tailer.follow( delay ), tailer.stop )
 
cs

 

 

1-2. 실행 파일 작성 - run.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# run.py
import tailer
 
file = open("test.log""r", encoding="utf-8")
follow, stop = tailer.follow(file)
 
stop_line_cnt = 0
 
for line in follow:
  print(line)
  
  # 5개의 라인 출력 후 종료
  stop_line_cnt += 1
  if stop_line_cnt >= 5:
    stop()
cs

 

 

1-3. 테스트 로그 - test.log

  - 메모장 같은 텍스트 편집기로 로그를 입력.

 

 

 

2. 실행
2-1. 실행 명령어 입력
python run.py

 

 

2-2. 실행 결과

 

 

 

마치며 

  - Python으로 파일을 다룰 때, 내용을 전체 쓰거나 읽는 정도로만 썼었는데 [ tail --follow ] 기능을 구현하면서 seek에 대해서 알게되었다.

  - seek를 활용하면 [ tail --follow ] 뿐만 아니라, [ tail --lines ]도 충분히 구현이 가능할 것이다.

 

 

 

댓글