파이썬3 노트

외부 서비스의 데이터를 python으로 slack에 통지하기

Jonchann 2020. 4. 14. 17:52

slacker 설치하기


먼저 slacker를 설치한다

$ python3 -m pip install slacker

slacker의 공식 github 링크를 타고 들어가면 예시들을 볼 수 있다.

slack에서 token과 webhook url 가져오기


token 취득

token은 코드에서 slack을 초기화할 때 쓰인다.

from slacker import Slacker


slack = Slacker('your_token')

token에는 4가지 종류가 있다.

1. bot: 어플리케이션이 독립적으로 작동하며 user token과 동일하게 개별 범위를 설정할 수 있음
2. user: 사용자를 대신해 사용자가 어플리케이션에 부여하는 OAuth 범위에 따라 작동함
3. workspace: 워크스페이스 어플리케이션에 속하며 workspace token과 함께 새로운 어플리케이션을 만드는 것은 추천하지 않음
4. legacy: legacy token 생성기로 생성되는데 이제는 사용을 추천하지 않음

여기서 사용하는 token은 bot OAuth 토큰인데 처음 시작할 때 Incoming Webhooks를 선택해서 들어오면 알아서 xoxb-xoxp-로 시작하는 token을 만들어준다.

  • 새로운 어플리케이션을 만든 후 settingsInstall App 혹은 FeaturesOAuth & Permissions에서 찾을 수 있다.

xoxp-로 시작하는 토큰을 사용해 코드를 짜면 실제 사용자 프로필을 사용해 slack에 메세지를 보낸다.
xoxb-로 시작하는 토큰을 사용해 코드를 짜면 본인이 API에서 설정한 프로필을 사용해 slack에 메세지를 보낸다.

  • bot을 사용할 채널에서 앱을 추가해주어야 사용할 수 있다.

webhook url 취득

webhook url은 외부 소스를 받아 slack에 통지할 때 사용하는 주소이다.
token이 같다면 webhook은 권한을 나누는 용인 것 같고 일단 scope에 Incoming Webhook이 추가되니 메세지 통지에는 적합한 것 같다.

from slacker import Slacker

slack = Slacker('your_token', 'webhook_url')

전에는 webhook url을 워크스페이스 어플리케이션-커스텀 인티그레이션에서 Incoming Webhook이라는 어플을 통해 각 채널에 대한 통지 메세지를 날렸다고 하는데 지금은 전혀 달라서 어플리케이션을 만들고 각 채널마다 Incoming Webhooks를 생성해야하게 되어있다.

즉, 하나의 webhook url로는 하나의 채널에만 통지를 보낼 수 있다.
여러 채널에 여러 webhook url을 사용해 통지 메세지를 보내는 것은 가능하지만 json payload를 통한 채널 변경은 불가능하다.
코드나 POST에서 소스를 보내는 서비스 혹은 채널을 변경하는 것이 안된다는 거다.

scope 정하기


OAuth & Permissions에서 내려가보면 Scopes라는 것이 나온다.
slacker가 어디까지 할 수 있는가에 대한 허용범위를 정하는 곳이다.

처음에 Incoming Webhooks를 선택해 어플리케이션을 만들었다면 이 곳 Bot Token ScopesIncoming Webhooks라는 범위가 설정되어 있을 것이다.

하지만 slacker.Error: missing_scope가 나온다.

몇개 더 추가해준다.

새로운 scope를 설정할 때마다 reinstall app을 해야하는데 이 때마다 새로운 webhook url이 발급된다.

아직 어떤 scope를 부여하고 부여하지 않아도 slack에 메세지를 보낼 수 있는지 확인해보지는 못했으나 아래와 같이 설정했을 때 제대로 작동하는 것을 확인했다.

slacker로 slack에 메세지 보내는 class


먼저 slack을 초기화 할 설정값을 json으로 작성한다.
이 코드는 notify와 warning을 보내는 채널이 다르기 때문에 webhook_url도 2개 필요하다.

{
"slack_notify": {
        "incomingWebHook": "webhook_url_of_notify_channel",
        "OAuthToken": "OAuth_token_of_workspace"
    },
    "slack_warning": {
        "incomingWebHook": "webhook_url_of_warning_channel",
        "OAuthToken": "OAuth_token_of_workspace"
    }
}
from slacker import Slacker
from get_info import get_connect_info


class SlackSender:
    def __init__(self, purpose: ('notify', 'warning')):
        slack_config = self.get_config(purpose)
        self.slack = Slacker(
            token=slack_config['OAuthToken'],
            incoming_webhook_url=slack_config['incomingWebHook']
        )

    def send(self, channel: str, text: str, user_name: str, icon: str, attachment=None):
        payload = {
            "channel": channel,
            "text": text,
            "username": user_name,
            "icon_emoji": icon,
        }
        if attachment is not None:
            payload["attachment"] = attachment

        self.slack.chat.post_message(**payload)

    def upload(self, file):
        self.slack.files.upload(file)

    def get_config(self, purpose):
        return get_connect_info(f'slack_{purpose}')


if __name__ == "__main__":
    notify_sender = SlackSender('notify')
    warning_sender = SlackSender('warning')

    notify_sender.send(
        channel="[channel_name]",
        text="notify test",
        user_name="[user_name]",
        icon=":innocent:",
        )

    warning_sender.send(
        channel="[channel_name]",
        text="warning test",
        user_name="[user_name]",
        icon=":scream:",
    )

slacker가 내놓는 여러가지 에러


missing_scope 에러

권한(scope)이 부족한 경우

not_in_channel 에러

채널 이름은 틀리지 않았지만 부여한 token과 채널이 일치하지 않았을 때
해당 채널에 생성한 어플리케이션이 설치되어있지 않을 경우:

  • token을 xoxb-로 시작하는 것을 사용하고 다음을 설정함
  • 채널 설정
  • view channel details
  • Apps
  • Add App

channel_not_found 에러

이름이 틀렸을 때

icon을 다르게 해서 초기화했는데 같은 icon으로 메세지가 가는 에러

webhook url을 발급한 채널이 같을 때

  • 발급한 채널이 같은 채로 다른 채널에 보내도 사실 가긴 함
  • 하지만 다른 설정값이 적용되지 않을 수 있음