ClickOnceアプリケーションの配布をGitHub Pagesでできないか試したら警告が来た
ClickOnceアプリケーションの配布はHTTPで更新ファイルを参照できさえすれば動作するはず。 それならGitHubのリポジトリ上でも実現できるのではないかと思ったのでやってみました。
といっても既にGitHubでの運用を検討されている方はおられるわけで。 どうやらリポジトリにプッシュしたファイルを参照する場合、応答ヘッダが異なるため上手くいかないようです。
GitHub Pages
それなら、(多分大丈夫だろうと思いつつ)GitHub Pages上に配布ファイルを配置した場合の動作はどうなのか。
以前はリポジトリにGitHub Pages用のgh-pagesブランチを切ったうえでHTMLファイルなりを配置する必要がありました。 この状態だとコードはmasterブランチ、ClickOnceで配布するファイルはgh-pageブランチへプッシュする必要があるのですが、 現在はmasterブランチ上でGitHub Pagesも管理できるようになっています。
masterブランチでGitHub Pagesを管理する方法
リポジトリのSettings→GitHub Pagesでmaster branch
を選択し、リポジトリルートにdocs
ディレクトリを作成します。
この/docs
ディレクトリ配下にHTMLファイルなりを配置し、https://(user_name).github.io/(repository_name)
にアクセスすると、リポジトリのGitHub Pagesが表示されるようになります。
ClickOnceアプリケーションの配置
コードブランチとGitHub Pagesブランチを分ける必要が無いのであれば、ClickOnceの発行先を/docs配下に設定し、 ビルドとClickOnceのアプリケーション発行後にリポジトリにプッシュすれば大した手間もかからずアプリケーションの配布環境が構築できるはずです。
GitHub Pages用ディレクトリ(ClickOnceアプリケーションの配布環境)を含んだmasterブランチの構成を以下の状態にしてmasterブランチへプッシュしてみます。
/ClickOnceApp(master) ┝.git ┝/ClickOnceApp(アプリケーション) ┝/docs(GitHub Pages配置ディレクトリ・ClickOnce配布用) |┝Application Files |┝ClickOnceApp.application |┗setup.exe ┝.gitattributes ┝.gitignore ┝ClickOnceApp.sln ┝LICENSE ┗README.md
GitHubから警告メールが届く
上記の構成でリポジトリにプッシュしたところ、ClickOnceでのアプリケーションアップデートを実施することができました。 ビルドついでに発行するだけなので手間にもならないしこれはこれで良いのではと思ったのですが、 リポジトリへのプッシュ直後にGitHubから警告のメールが届いていました。
GitHub Pagesでバイナリファイル公開しているならRelease機能を使いなさいとのこと。その通りなので何とも言えません。*1 ちなみに、リポジトリ内にバイナリファイルがあるとプッシュするたびに警告メールが届きつづけるみたいです。
The page build completed successfully, but returned the following warning for the
master
branch:
It looks like you're using GitHub Pages to distribute binary files. We strongly suggest that you use releases to ship projects on GitHub. Releases are GitHub's way of packaging and providing software to your users. You can think of it as a replacement to using downloads to provide software. We found the following file(s) which may be a good candidate for releases: package/setup.exe. For more information, see https://help.github.com/articles/about-releases/.
For information on troubleshooting Jekyll see:
https://help.github.com/articles/troubleshooting-jekyll-builds
If you have any questions you can contact us by replying to this email.
結論
ClickOnceのアプリケーション配布自体は可能だったのですが、GitHubが推奨する使用方法ではないのでやるべきではないです。
配布するアプリケーションバージョン管理が必要になったら、CodeCommitからS3にデプロイするのが現実的に考えて楽なのかなと思っています。何となく。
警告でアカウントがBANされても困るのでGitHubのサポートにメールで謝っておきました。
GitHub実践入門 ~Pull Requestによる開発の変革 (WEB+DB PRESS plus)
- 作者: 大塚弘記
- 出版社/メーカー: 技術評論社
- 発売日: 2014/03/20
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (23件) を見る
わかばちゃんと学ぶ Git使い方入門〈GitHub、Bitbucket、SourceTree〉
- 作者: 湊川あい,DQNEO
- 出版社/メーカー: シーアンドアール研究所
- 発売日: 2017/04/21
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (3件) を見る
*1:rawgitというサービスを使えばReleaseにアップしたデータを参照できるらしい。
DataGridView上のデータを絞り込み表示する
DataGridViewに表示されているデータに対して、絞り込み条件を指定し表示させたい場合は BindingSourceクラスのFilterプロパティが使用できる。
BindingSource.Filter プロパティ (System.Windows.Forms)
手順
- DataGridViewにバインドしたDataSourceをDataTableとして取得する。
- DataTableをBindingSource.DataSourceプロパティにセットする。
- BindingSource.Filterプロパティに絞り込み条件を設定する。
- Filterに設定した条件で絞り込みされた結果がDataGridViewに表示される。
フォーム上のテキストボックスに入力された値がDataGridViewに対しての絞り込み条件としたとき、 TextChangedイベントが発生するたびにフィルター処理を呼ぶようにハンドラを追加する。 見かけ上分かりやすかったのでTextChangedをイベントに指定しているが、このイベント自体は別に何でも良い。
''' ロード時の初期設定 Private Sub Form_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load ' テキストボックスに変更があった場合のイベントハンドラを追加する AddHandler txt_Condition.TextChanged, AddressOf DataGridViewFilter End Sub
テキストボックスがTextChangedイベントを発生するたびに呼び出される関数上で、 絞り込み条件の記述を整形し、BindingSourceにデータと絞り込み条件を設定する。
Private Sub DataGridViewFilter() Dim objBind As BindingSource Dim objData As DataTable Dim strFilter As String ' DataGridViewにバインドしたデータをDataTableとして取得する objData = CType(DataGridView1.DataSource, DataTable) ' データが存在する場合 If IsNothing(objData) = False Then objBind = New BindingSource ' バインドするデータソースにDataTableをセット objBind.DataSource = objData ' DataGridViewの表示内容を絞り込むための条件式を設定する strFilter = "Color like '%" & txt_Condition.Text & "%'" ' データソースにフィルターをセット objBind.Filter = strFilter End If End Sub
DataGridViewが以下の状態で表示されている場合、
Seq | Month | Day | Color |
---|---|---|---|
1 | 8 | 1 | Orange |
2 | 4 | 17 | Blue |
3 | 9 | 19 | Light Pink |
4 | 3 | 4 | Yellow |
5 | 9 | 21 | Pink |
6 | 7 | 13 | White |
7 | 1 | 1 | Red |
8 | 2 | 10 | Green |
9 | 6 | 13 | Purple |
テキストボックスにPink
と入力があった場合、DataGridViewに対する絞り込み条件はColor like '%Pink%'
となる。
あとはこの条件式をBindingSourceにセットすることでDataGridViewの表示状態は以下のように変更される。
Seq | Month | Day | Color |
---|---|---|---|
3 | 9 | 19 | Light Pink |
5 | 9 | 21 | Pink |
記述した内容だと入力の都度TextChangedイベントが発生してしまう。
絞り込みの条件句を部分一致にしているので、P
と入力した時点でTextChangedイベントが発生し、
Light Pink
、Pink
、Purple
の3件が表示される。
このあたりの振る舞いは別のイベントで制御するほうがスマートかもしれない。*1
この記事は今度書き直す。
*1:とはいえEnterキーとか検索ボタンをトリガーにしたくないという要望があってこのまま実装した。
ヤマハRTX1200から出力したログをLogstashを使用してelasticsearchに登録、Kibanaで可視化してみた
ヤマハRTX1200のsyslogにURLフィルターのログを出力するようにしています。 このURLフィルターのログをLogstashを使用してelasticsearchに登録し、kibanaで可視化してみました。
使用するログ
syslog全体から以下のログを抜き出しテストで使用しました。
2018/02/08 00:50:07: [SD] Logfile is opened("sd1:rt_syslog.log", maximum size: 455524352 bytes) 2018/02/08 00:50:32: [URL_FILTER] Passed at LAN1 IN(2) filter: 192.168.1.2 : http://www.hatena.ne.jp/ 2018/02/08 00:50:32: [URL_FILTER] Passed at LAN1 OUT(1) filter: 192.168.1.2 : http://www.hatena.ne.jp/ 2018/02/08 01:03:39: [URL_FILTER] Passed at LAN1 IN(2) filter: 192.168.1.2 : http://weathernews.jp/pinpoint/cgi/search_result.fcgi?service=11&lat=&lon=&ameno=67437&name=広島&pref=67 2018/02/08 01:03:39: [URL_FILTER] Passed at LAN1 OUT(1) filter: 192.168.1.2 : http://weathernews.jp/pinpoint/cgi/search_result.fcgi?service=11&lat=&lon=&ameno=67437&name=広島&pref=67 2018/02/13 19:43:51: LAN1: PORT8 link down 2018/02/13 19:43:53: LAN1: PORT8 link up (10BASE-T Full Duplex) 2018/02/13 19:44:33: LAN1: PORT8 link down 2018/02/13 19:44:35: LAN1: PORT8 link up (1000BASE-T Full Duplex) 2018/02/12 17:36:34: [URL_FILTER] Passed at LAN1 IN(2) filter: 192.168.1.2 : http://b.hatena.ne.jp/js/hatena_dfp2.js 2018/02/12 17:36:34: [URL_FILTER] Passed at LAN1 OUT(1) filter: 192.168.1.2 : http://b.hatena.ne.jp/js/hatena_dfp2.js 2018/02/14 19:10:32: [EXTMEMBOOT] Configuration file was not found. 2018/02/14 19:10:32: [EXTMEMBOOT] Firmware file was not found. 2018/02/15 01:14:05: [URL_FILTER] Passed at LAN1 IN(2) filter: 192.168.1.2 : http://www.yahoo.co.jp/ 2018/02/15 01:14:05: [URL_FILTER] Passed at LAN1 OUT(1) filter: 192.168.1.2 : http://www.yahoo.co.jp/ 2018/02/15 01:18:23: [URL_FILTER] Passed at LAN1 IN(2) filter: 192.168.1.2 : http://hatenablog.com/?via=201002 2018/02/15 01:18:23: [URL_FILTER] Passed at LAN1 OUT(1) filter: 192.168.1.2 : http://hatenablog.com/?via=201002
Grokフィルターパターンの作成
このログをGrokフィルターで項目ごとにパースします。
ログの中でYYYY/MM/DD HH:MM:SS: [URL_FILTER]...
からはじまるデータのみ対象になるようフィルターパターンを作成します。
Grokのパターンは以下を参照しました。 logstash-patterns-core/grok-patterns at master · logstash-plugins/logstash-patterns-core · GitHub
フィルターパターンはGrok Debuggerを使用しながら作成しました。 Grok Debuggerは入力したいログとパターンを入力することでテストしながら作成ができて便利です。
今回は以下のようなフィルターパターンを作成しました。*1
%{YEAR:year}/%{MONTHNUM:month}/%{MONTHDAY:day}\s%{HOUR:hour}:%{MINUTE:min}:%{SECOND:sec}:\s*\[URL_FILTER\]\s*Passed\s*at\s*LAN%{INT:lan}\s*%{WORD:inout}\(%{INT:filter}\)\s*filter:\s*%{IP:clientip}\s*:\s*%{URIPROTO:uriproto}://(?:%{USER:user}(?::[^@]*)?@)?(?:%{URIHOST:urihost})?(?:%{URIPATHPARAM:uriparam})
Logstashの設定・起動
作成したフィルターパターンをlogstash/conf.d/pipeline.conf
に記述します。
$ sudo /etc/logstash/conf.d/pipeline.conf
ログファイルは先頭から読み込みます。 テストなのでインデックスも特に指定していません。
input { file { path => "/home/urlFilter.log" start_position => "beginning" } } filter{ grok { match => ["message", "%{YEAR:year}/%{MONTHNUM:month}/%{MONTHDAY:day}\s%{HOUR:hour}:%{MINUTE:min}:%{SECOND:sec}:\s*\[URL_FILTER\]\s*Passed\s*at\s*LAN%{INT:lan}\s*%{WORD:inout}\(%{INT:filter}\)\s*filter:\s*%{IP:clientip}\s*:\s*%{URIPROTO:uriproto}://(?:%{USER:user}(?::[^@]*)?@)?(?:%{URIHOST:urihost})?(?:%{URIPATHPARAM:uriparam})"] } } output { elasticsearch { hosts => ["localhost:9200"] } }
Logstashを起動しelasticsearchにデータを登録します。
$ sudo service logstash start
elasticsearchの確認
elasticsearchにデータが登録されているか見てみます。
$ curl -XGET localhost:9200/_cat/indices?v
テストで使用したログ17行が取り込まれています。
インデックスは指定しなかったのでlogstash-2018.02.17
で作成されています。
$ curl -XGET localhost:9200/_cat/indices?v health status index uuid pri rep docs.count docs.deleted store.size pri.store.size yellow open .kibana 9fT-tqMkRfq0mG30uGXBug 1 1 1 0 3.2kb 3.2kb yellow open logstash-2018.02.17 lvliGqYrSV6GFuVyW2DKcQ 5 1 17 0 57.5kb 57.5kb
kibanaで可視化
kibanaで取り込んだデータを見てみます。 Discoverでelasticsearchにデータを取り込んだ時間ごとの件数と生のデータを見ることができます。
取り込んだデータを選択するとGrokフィルターに記述した通りにデータがパースされている事が確認できます。
Grokフィルターでパース出来なかったデータについては、tagsに_grokparsefailure
と記述されています。
取り込んだテストデータの1行目、6~9行目、12、13行目が該当していました。
取り込んだデータが想定通りにパースされていたのでVisualizeで可視化してみます。 Pieチャートでデータを見てみたところ、初期状態では取り込んだ全17件がCountで表示されています。
urlhost単位で件数を見るため、buckets項目でSplit Slicesを選択し、AggregationでTerms、Fieldでurlhost.keywordを選択します。 設定後、Apply Changes(▷ボタン)をクリックするとチャートが分割されます。 ここでチャート内にカーソルを当てると各データのカウントを見ることが出来ます。
このとき、テストで使用したデータの17件のうち7件はGrokフィルターに当てはまらなかったデータになるのでチャートの対象は10件になります。
逆にTermsでtags.keywordを選択すると、10件のデータにはtagsに値が無いので_grokparsefailure
の7件が結果として表示されます。
同じ要領でVisualizeからData Tableを選択します。 Split RowsでAggregationでTerms、Fieldでurlhost.keywordを選択すると各データの件数が表示されます。
Visualizeは画面右上のSaveから設定を保存することができます。
さらにデータを取り込んだ結果
Grokフィルターでデータをパースできることを確認できたので、とりあえず手元にあるデータ150000件を登録してみました。 パッと見た感じやはりというか広告、CDNと思われる場所とのアクセス数が多い気がします。
Pieチャートとは別にVertical Barで日ごとのアクセス先が可視化できるようにしました。*2 Kibanaの運用は当面これでやっていこうと思います。
データ分析基盤構築入門[Fluentd、Elasticsearch、Kibanaによるログ収集と可視化]
- 作者: 鈴木健太,吉田健太郎,大谷純,道井俊介
- 出版社/メーカー: 技術評論社
- 発売日: 2017/09/21
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (2件) を見る
*1:syslogで対象としたいログはこれだけではないので、フィルターはGistで更新していく。https://gist.github.com/mamori017/14b3ea1b809a797042bb0232214e4a52