이슈 : 쿼리로 한번에 가져온 결과와 쿼리를 각각 가져와 가공해 만든 groupby 결과가 매우 다름

원인 : member number 같은 series가 object로 잡혀있는데 concat 하는 과정에서 각각 다른 type으로 인식됨. None이나 'nomember' 같은 값이 있느냐에 따라 type이 무엇으로 인식될지가 결정.

조치 : 해당 series의 type을 str로 명시함.

 

다음부터는 ddl로 type도 맞추고 들어가는 습관을 들이면 좋겠다

스튜디오 레벨 디버깅의 활용

uipath studio에서는 디버깅 모드 실행을 제공한다.

디버깅 모드는 지정된 포인트 혹은 에러에 도달했을 때, 멈춰서 변수들이나 현재 프로세스의 상태를 보여주는 모드이다.

활용 방식

1. Breakpoint

2. Locals

3. Watch

4. Immediate

 

1. Breakpoint [단축키 F9]

- breakpoint는 잠깐 멈추는 지점을 의미한다. [다른 언어들도 공통되는 개념]

- breakpoint로 지정된 line(또는 activity)은 실행되지 않고 그 직전까지 실행된다.

- breakpoint로 지정하면 빨간색 표시가 뜬다.

- breakpoint로 멈추는 것에 조건을 줄 수도 있다. 그렇게 설정하면 해당 포인트에서 특정 조건이 달성되면 멈춘다.

Conditional Breakpoint

- 해당 지점에서 멈췄을 경우 Log도 따로 지정 가능하다. 이런 기능을 사용하면 로깅을 위해 굳이 if문을 만들어줄 필요가 없다. 특히 output datatable 같은 거 해서 로그 찍어놓고 확인하는 그런 경우가 많은데 굳이 그럴 필요가 없다. [이 setting도 있지만 아래에서 소개하는 기능을 활용하는 게 훨씬 편하다.]

- 스위치는 bulk로 끄고 켤 수도 있다. 

위쪽 버튼을 활용하면 한꺼번에 껐다가 한꺼번에 켰다가 할 수도 있다.

2. Locals

- Locals에는 현재 break된 곳에 있는 모든 변수의 상태값을 보여준다.

- breakpoint와 함께 활용되어 실제 값이 어떻게 들어가는지 간단하게 볼 수 있다.

- 연필모양을 누르면 값을 볼 수 있고, 값을 편집하고 그 상태로 이어서 수행하는 것도 가능하다.

Locals의 예시. break된 scope에서 call할 수 있는 변수가 모두 나온다.

3. Watch

- 변수들의 특정값을 지정해서 추적할 수 있다.

- 가령 Locals에서는 dtContainer의 값을 보여주지만, dtContainer.AsEnumerable.Skip(i_irownum).Take(i_itakenum).CopyToDataTable 같은 값은 보여주지 않는다. 하지만 그런 값을 디버깅할 때 추적해야 한다면 여기에 기입하고 추적하면 된다.

 

4. Immediate

- 값을 쓰면 즉각적으로 표시된다. 다른 언어로 치면 terminal이나 console창 느낌으로 보면 된다.

- 예를 들어, dtContainer를 쓰면 dtContainer의 내용이 표시된다.

- 추적할 값으로 설정할 필요는 없으나 즉각적으로 어떤 변수의 값을 확인하고 싶은 경우 활용할 수 있다.

- dayofweek같은 걸 추적으로 찍어놨는데 dayofweek의 .ToString('d')값과 .Tostring('g')값이 어떤 차이가 있는지 같은 걸 확인할 때 많이 쓴다.

- 드물게 특정값을 편집하는 용도로 쓸 수도 있다.

'RPA Uipath > Uipath 디버깅' 카테고리의 다른 글

[Uipath] AR 봇 연결 끊김 이슈  (0) 2024.07.31
Uipath의 디버깅 시리즈1  (0) 2023.06.10

0. 디버깅에 관해

1. console 또는 log 찾기

2. 윈도우 환경

3. 브라우저

4. 네트워크

--------------------------------------------------------------------------------------------------------------------------------------------------------

0. 디버깅에 관해

개발자 업무의 절반 이상은 디버깅이다.

그럴 수밖에 없는 것이 어떤 service를 만드는 기간이든

그걸 운영하는 기간이든 간에 에러와 시행착오는 항상 존재하기 때문이다.

따라서 얼마나 적확하게 디버깅을 하느냐가 개발과 운영을 잘하느냐를 결정한다.[각주:1]

 

우리는 모든 에러를 겪어볼 수 없다.

새로운 에러는 언제든 등장하고 원인을 분석하고 해결하는 일은 개발자의 몫이다.

이 시리즈에서는 RPA, Uipath를 개발하는 입장에서 디버깅을 어떻게 할 수 있을까에 대해 정리를 해보려고 한다.

먼저 이번 글에서는 디버깅을 하기 위한 근거를 어떻게 찾아야 되는지를 다루려고 한다.

 

1. console 또는 log 찾기

  제대로 된 프로그램이라면 에러가 나든 안 나든 진행상황에 관해 어디든 찍어놨을 가능성이 높다.

보통 그것들은 console이라 불리는 곳에 찍히거나 log가 쌓이는 곳에 적재된다.

에러가 발생했다면 기본적으로는 다루는 툴의 console이나 log 위치를 찾아보고 파악해야 한다.

그 위치는 로컬일 수도 있고, 오케스트레이터 서버일 수도 있고 또는 타겟 프로그램일 수도 있다.

Uipath 기준에서는 가장 기본이 되는 로컬 로그나 오케 로그를 우선적으로 체크해야 한다.

 

2. 윈도우 환경

  RPA 환경은 윈도우 환경이다. 이렇게 단정적으로 말하는 이유는 linux나 mac은 일반적으로 전문가 영역이기 때문이다.

유저도 적을 뿐더러 그런 영역에서는 굳이 RPA를 써가며 자동화할 일이 거의 없다.

다행히도 윈도우에서는 이벤트 뷰어라는 강력한(?) 로깅툴이 존재한다.

이벤트 뷰어

윈도우에서 일어나는 대부분의 행위는 여기에 로그가 찍힌다.

어떤 계정으로 몇시 몇분에 로그인이 됐고 무슨 프로그램을 설치 또는 설치 실패했으며,

어떤 서비스가 돌다가 인증을 실패했고 뭐 그런 로그들이다.

보통 응용 프로그램에 우리가 찾는 로그들이 많이 찍혀있다.

여기까지 찾아온다는 것은 'uipath 로그에서는 원인이 애매하게 찍혀있는데 화면으로 봐도 특별한 뭐가 없고 에러는 왜인지 모르겠는데 자꾸 발생한다'는 경우다.

 

3. 브라우저

  RPA 과제들은 브라우저로 접속해서 데이터를 추출하는 경우가 많다.

브라우저는 html을 해석하고 api를 호출해주는 툴이기 때문에 자체적인 console이 아주 잘 발달돼 있다.

F12를 누르면 개발자 도구가 뜬다.

글을 작성하는 와중에 자동저장이 호출되는 것을 볼 수 있다.

여기서 콘솔탭을 누르면 웹페이지가 로드되면서 나오는 로깅을 볼 수 있다

굉장히 깔끔한 콘솔

웹에서 특정 버튼을 눌렀는데 평소엔 잘 되다가 반응이 갑자기 안 된다? 그럼 여기서 이유가 다 찍힌다.

나오는 문구로 구글링을 해보자.

Elements 탭에서는 다음과 같이 Css selector를 copy할 수 있는데

구조 변경 등으로 인해 셀렉터가 안 잡히거나, 데이터 스크래핑이 안 되는 경우

이 기능으로 비교해보면서 빠르게 디버깅이 가능하다.

이 정도면 크롬이 무거워도 용서해주자....

ctrl + f로 검색하거나 모바일 크기로 줄이기 같은 기능들도 아주 유용하다.

 

4. 네트워크

네트워크 영역은 대부분 최초 환경 세팅에서 디버깅하게 된다.

결국은 방화벽 문제일 가능성이 높고, 회사 내부 정책에 따라 조치해야 한다.

RPA 개발자 입장에서 문제는 보안 담당자가 '뚫어는 줄텐데 뭐 뚫어줘야 되는지는 너가 알아서 가져와'라고 했을 때이다.

그럼 Trigger후 Traffic 변화를 로깅해주는 것이 필요하다.

다양한 툴이 있겠으나 wireshark로 소개한다.

찾을 때 눈이 좀 아프긴 하다

일반적으로는 이런 디버깅을 경험하진 않는다.

보통 벤더사나 솔루션사에서 클라우드 서비스를 해주는 과정에서

뚫어줘야 하는 url을 정확히 알고 있어야 되는데 대충 알고 있거나 빠뜨렸을 때,

또는 그 회사에서 일반적이지 않은 방화벽 정책을 쓰느라 이상한 곳에서 막혔을 때,

혹은 방화벽 관리자가 안 풀어놓고 풀었다고 거짓말하는 거 같을 때,

그럴 때 울며 겨자먹기로 깔아서 눈을 살짝 혹사시키지만 근거를 찾을 수 있는 패킷 분석 툴이다.

회사가 엄청 크고 엄격한 곳이 아니라면 방화벽 담당자를 찾아가서,

'저 혹시 제가 이러이러한 기능이 막혀서 그러는데 제가 트리거하면 그거 리스트 같이 보고 해제할 목록 좀.....'이라고 하는 게 속편하다.

다행히도 Uipath는 나름 docs에 이 정보가 적혀있다.

https://jnaul.tistory.com/260

 

IP Resolution 관련 Cloud Orchestrator 세팅

일반적으로 Hostname을 *를 붙여 요청하면 방화벽을 해제해 주지만 간혹 IP Resolution 형태라 IP질의가 무조건 확인돼야만 방화벽을 해제해주는 사이트들이 있다. Cloud로 오케스트레이터를 설치하는

jnaul.tistory.com

https://docs.uipath.com/automation-cloud/automation-cloud/latest/admin-guide/configuring-your-firewall-for-automation-cloud

 

https://docs.uipath.com/automation-cloud/automation-cloud/latest/admin-guide/configuring-your-firewall-for-automation-cloud

 

docs.uipath.com

 

  1. 엄밀히 말하면 요구사항과 scope의 정의나 PI 등도 그 영역에 포함되지만 여기선 소스 관점에서 다뤄보려고 한다. [본문으로]

 

today = date.today()
date_list = []

for n in range(1, 3):
	days_to_monday = (7 * n - today.weekday())	
	days_to_saturday = (13 * n - today.weekday())
	date_list.append(today + timedelta(days=day_to_monday))
	date_list.append(today + timedelta(days=day_to_saturday))
date_list.sort()

간단히 설명하자면,

weekday는 0부터 6까지의 정수값을 가지는 요일값이다.

0은 월요일이기 때문에 그 주의 월요일에 해당하는 날은

기준시점에서 weekday를 빼면 나오게 된다.

이때 다음주 월요일을 알고싶다면 여기서 7일을 더해주면 된다.

따라서 특정 주차 후 월요일을 알고 싶다면 n*7 - weekday 만큼을 기준 날짜에 더해주면 된다.

 

 

SQS: Simple Queue Service의 약자. AWS에서 나온 큐 서비스다. 큐를 쏴놓고 소진할 때까지 받으면 되기 때문에 멀티 프로세싱이나 로그 밸런싱 하기가 쉽다. FIFO로 할 건지 무작위로 할 건지 선택할 수 있다. 무작위로 하면 들어온 순서와 무관하게 큐를 준다. 매월 백만개까지는 무료라고 하니 로깅이나 마스터 정보 수준의 크기가 아니라면 가볍게 쓸만한 거 같다. 유료 수준으로 넘어가도 백만개당 0.5불 정도다.

Kafka: 아키텍쳐내에 여러 시스템이 등장하면서 데이터의 복잡성이 커지자 교통정리를 해주고 메시지, 이벤트에 대한 최적화, 로드 밸런싱이 필요해지게 되었다. 그래서 등장한 개념이 이벤트 트리거, 메시지 트리거들이다. 보통 이벤트 트리거들은 메시지를 따로 저장하기 때문에 캐싱이 되고 메시지 트리거 역할도 할 수 있다. 카프카는 이벤트 트리거로서 시스템 간의 데이터 transfer 주체를 producer, consumer로 나누고 내부에 topic - partition을 둠으로써 각 주체가 topic별 트리거링을 할 수 있게 해뒀다. consumer가 메시지를 요청(poll)하면 fetch가 돼있는 경우 fetch된 곳에서 자료를 갖다주며, 아닌 경우 partition에서 레코드를 갖다 준다.

작업을 하다보면 코드로 매핑해야 되는 케이스가 자주 생긴다.

이럴 때 np.where를 쓸 수도 있지만 케이스가 4~5개 생기는 경우 소스 가독성, 퍼포먼스가 떨어지게 된다.[각주:1]

또 apply를 써서 한 줄 한 줄 dict.get()으로 넣으면 가독성은 좋지만 퍼포먼스가 떨어진다.[각주:2]

이때 가독성도 좋고 퍼포먼스도 좋은 함수가 있었다.

series.map이다.

매핑된 dict를 작성하고 map하면 코드매핑이 된 시리즈를 생성할 수 있다.

test_dict = {1: 'a', 2: 'b', 3: 'c', 4: 'd'}
df['colB'] = df['colA'].map(test_dict).fillna('매핑 안 되는 것들 Default value')

 

정리하자면,

1. 단순 dict 조건으로 매핑이 필요하면 series.map을 쓰자

2. 각 row별 함수를 적용해야 하는 경우는 apply를 쓰자

  1. [np.where(df['colA'] == 1, 'a', np.where(df['colA'] == 2, 'b', np.where(df[colA] == 3, .......)))] 무슨 프랙탈 구조처럼 된다. [본문으로]
  2. df['colB'] = df['colA'].apply(lambda x: test_dict.get(x, '기본값')) apply가 자유도는 높지만 퍼포먼스가 그리 좋진 않다. 어쩔 수 없이 row별 함수처리를 해야하거나 퍼포먼스 차이가 크지 않을 때만 사용하자. [본문으로]

'파이썬' 카테고리의 다른 글

파이썬을 인터프리터 언어라고 하지 말자  (0) 2023.08.18
주차별 특정 요일 따오기  (0) 2023.05.02
[Python] 날짜 변수명 짓기  (0) 2022.10.19
[Python] 데이터 언패킹  (0) 2022.10.19
파이썬 프로젝트 진행  (0) 2022.09.06

+ Recent posts