信頼はずっと、挑戦はもっと。

お問い合わせ
TEL:03-3496-3888

BLOG コアテックの社員ブログ (毎週月曜~金曜更新中)

LIST OF ARTICLES

記事一覧

  • テクログ

    スプレッド演算子

    スプレッド演算子(可変長引数)【...】←この三点リーダーみたいなやつのこと読んで字のごとくですが、関数に渡す引数を任意の個数渡すことが出来ます。悩んでたんです、既に用意されている(実態がない)関数の引数が可変長だったのです。。。それをどのようにすれば、可変で引数を渡せるのか。その時に出会いました!!使用する機会が最近ありましたので、簡単な例を載せてご紹介いたします!<?php // [...]引数が過変数で受け取ることが可能 public function my_method (int ...$nums) {   // init   $sum = 0;   foreach ($nums as $num)   {     $sum += $num;   }   return $sum; } my_method(1,2,3,4,5);  // output = 15(引数が5つ) my_method(10,20,30);   // output = 60(引数が3つ) ...のように引数の数を可変で渡せる これは、かなり便利!!そうそう使う機会は多くはないとは思いますが、是非!「ここだ!」と思うタイミングで使ってみては?それでは、これにてm(_ _)m
  • テクログ

    CloudWatch Logsエージェントがローテートさせるとtimestamp is more than 2 hours in future.で止まってしまう件について

    こんにちわ。パグです。本日はCloudWatch Logsエージェントのログがtimestamp is more than 2 hours in futureで止まってしまう件について書きます。現在の環境はFuelPHPで、主にFuelPHPのローテートログをCloudWatchエージェントでPUSHさせたいって内容になっています。が、恐らく他の環境のログの場合で起きた事象もこれに近しいのではないかと思います。CloudWatchLogsエージェントは導入済みで、ローテート時にうまく動かない人向けなので、そもそもCloudWatchLogsにログが反映されていない場合は別の要因によるのではないかと思います。[/server/fuelphp/logs] datetime_format = %Y-%m-%d %H:%M:%S file = /path/to/fuel/app/logs/20*/*/* buffer_duration = 5000 log_stream_name = {instance_id} initial_position = start_of_file log_group_name = /server/fuelphp/logs 他にマルチラインの設定などが必要かと思いますが、簡単に書くとこんな感じに設定。CloudWatch側では、log_group_nameで検索ができるようになりますが、翌日「 timestamp is more than 2 hours in future.」とエラーが出ておりPUSHイベントが動いていません。色々調べていて、皆大好きStackOverflowを見て見ると、以下のような記事が。https://stackoverflow.com/questions/40604940/cloudwatch-logs-acting-weirdhttps://forums.aws.amazon.com/thread.jspa?threadID=243092この記事の人に激しく同意>Yes I'm experiencing the issue too. Is there a way to reset the state file without doing this?うん。私もそう思うわ。それやらないでResetしたいんだよぉぉぉぉ。はい。じゃあ。本題です。awslogsのPUTイベントが失敗する原因は以下です。PutLogEvents オペレーションの制約に従って、次の問題によりログイベントまたはバッチがスキップされる場合があります。以下本家のマニュアルから抜粋https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/WhatIsCloudWatchLogs.html注記1.データがスキップされた場合、CloudWatch Logs エージェントはログに警告を書き込みます。2.ログイベントのサイズが 256 KB を超過した場合、ログイベントは完全にスキップされます。3.ログイベントのタイムスタンプが 2 時間以上未来の場合、ログイベントはスキップされます。4.ログイベントのタイムスタンプが 14 日以上過去の場合、ログイベントはスキップされます。5.ログイベントがロググループの保持期間よりも古い場合、バッチはすべてスキップされます。単一の PutLogEvents リクエストでログイベントのバッチが 24 時間実行されている場合、PutLogEvents オペレーションは失敗します。上記の3がこの「 timestamp is more than 2 hours in future.」というエラーにあたります。タイムスタンプが実行時間より2時間以上未来日になっているので、スキップしますとのことで、最初はUTCと日本時間のズレのせいかと考えたのですが、どうもズレている時刻が異なります。実行タイムスタンプの調べ方はStackOverflowに書いてある通りで「/var/lib/awslogs/agent-state」をsqlite3で検索(JSON形式で保存されているので実行された体の時刻を調べます)調べるストリームIDは/var/log/awslogs.logに出ています。2019-09-28 06:01:02,041 - cwlogs.push.stream - INFO - 12879 - Thread-1 - Removing dead reader [77cbf636732d4f124469c8ccb0f71abe, /logs/2019/09/27.php] 2019-09-28 06:01:02,041 - cwlogs.push.stream - INFO - 12879 - Thread-1 - Removing dead publisher [77cbf636732d4f124469c8ccb0f71abe, /logs/2019/*/*.php] 2019-09-28 06:01:02,044 - cwlogs.push.stream - INFO - 12879 - Thread-1 - Starting publisher for [77cbf636732d4f124469c8ccb0f71abe, /logs/2019/09/28.php] 2019-09-28 06:01:02,044 - cwlogs.push.stream - INFO - 12879 - Thread-1 - Starting reader for [77cbf636732d4f124469c8ccb0f71abe, /logs/2019/09/28.php] 上記の77cbf636732d4f124469c8ccb0f71abeです。(PATHはサイトの詳細が記載してあるので少し削りました)これを検索します。[root@server]# sqlite3 /var/lib/awslogs/agent-state SQLite version 3.7.17 2013-05-20 00:56:22 Enter ".help" for instructions Enter SQL statements terminated with a ";" sqlite> select * from push_state where k="8deaef1856dda2abe912ceedc4180f53"; 上記のkの部分にストリームIDを入れると、JSONからPUSHした時にイベントが出てきます。8deaef1856dda2abe912ceedc4180f53|{"start_position": 248, "source_id": "8deaef1856dda2abe912ceedc4180f53", "first_timestamp": 1570412666000, "first_timestamp_status": 1, "sequence_token": "49599891918873079124975725871068904036184047788058782002", "batch_timestamp": 1570412666866,  "end_position": 369}|2019-10-06T21:00:13|2019-10-07T01:44:32 このFirstTimestampとbatchtimestampが明らかに前日になっています。前日になっていますが、9時間ズレとかではありません。なのでUTCの問題ではありません。なんでかなーと調べていくと、書き込まれない時に、ローテートされた後のログストリームIDがずっと変わらないではありませんか。2019-09-28 06:00:58,041 - cwlogs.push.reader - INFO - 12879 - Thread-1346 - Reader is leaving as requested... 2019-09-28 06:01:02,041 - cwlogs.push.stream - INFO - 12879 - Thread-1 - Removing dead reader [77cbf636732d4f124469c8ccb0f71abe, /logs/2019/09/27.php] 2019-09-28 06:01:02,041 - cwlogs.push.stream - INFO - 12879 - Thread-1 - Removing dead publisher [77cbf636732d4f124469c8ccb0f71abe, /logs/2019/*/*.php] 2019-09-28 06:01:02,044 - cwlogs.push.stream - INFO - 12879 - Thread-1 - Starting publisher for [77cbf636732d4f124469c8ccb0f71abe, /logs/2019/09/28.php] 2019-09-28 06:01:02,044 - cwlogs.push.stream - INFO - 12879 - Thread-1 - Starting reader for [77cbf636732d4f124469c8ccb0f71abe, /logs/2019/09/28.php] 2019-09-28 06:01:02,045 - cwlogs.push.reader - INFO - 12879 - Thread-1348 - Replay events end at 384. 2019-09-28 06:01:02,045 - cwlogs.push.reader - INFO - 12879 - Thread-1348 - Start reading file from 74. 2019-09-28 06:01:02,045 - cwlogs.push.batch - WARNING - 12879 - Thread-1348 - Skip event: {'timestamp': 1569618001000, 'start_position': 74L, 'end_position': 153L}, reason: timestamp is more than 2 hours in future. 2019-09-28 06:09:30,216 - cwlogs.push.batch - WARNING - 12879 - Thread-1348 - Skip event: {'timestamp': 1569618569000, 'start_position': 153L, 'end_position': 229L}, reason: timestamp is more than 2 hours in future. ダメだった時のログはこんな感じで。Removing dead publisherしてるのにStarting publisherのストリームIDが変わらない。77cbf636732d4f124469c8ccb0f71abeこの場合、翌日になっているのにずっとタイムスタンプ上9月27日の朝6時とかになっているので、9月28日のPUSHとならずに、スキップされてしまいます。原因は、FuelPHPのログって、一番上位に<?php defined('COREPATH') or exit('No direct script access allowed'); ?> こんな感じの固定文言が出ているんですけど、こいつが前日とまったく同じなものだから、Startを前日のログから検索してしまって、日付がリセットされないーって内容でした。なので、FuelPHPはCoreの LogsClassをOverwriteして2019-10-01 08:26:02<?php defined('COREPATH') or exit('No direct script access allowed'); ?>タイムスタンプを突っ込んでやりました。2019-10-07 06:00:08,256 - cwlogs.push.stream - INFO - 14088 - Thread-1 - Removing dead reader [729a61c49dafeeb9472f9bc030510546, /logs/2019/10/06.php] 2019-10-07 06:00:08,261 - cwlogs.push.stream - INFO - 14088 - Thread-1 - Starting reader for [8deaef1856dda2abe912ceedc4180f53, /logs/2019/10/07.php] すると、ログに設定した日付を判別して、勝手にローテートされるようになりました。うまくローテーションがかからなくてログの一部が翌日になったら送れなくなった人はお試しください。(Sitemapって、エラーじゃないやんけとか、いわない。)ではでは〜。
  • テクログ

    ISUCON8の予選問題について、環境構築してみる

    ISUCON8の環境構築してみたISUCON、ご存知ですか?http://isucon.net/一言でいうと、WEBサービスのチューニングバトルです1回も出たことないですが、毎回盛り上がってるみたいです。今回はISUCON8の予選問題の環境構築をやってみました。公式やGitにもいろいろ書いてあるのですが・・・かなり苦戦しました・・・vagrantが入っていることが前提です。あとPHPです。1.ここに予選のアプリケーションのソースがあがっているので、自分のPCの好きなところにcloneしましょうhttps://github.com/isucon/isucon8-qualify2.ここに各種vagrantの設定ファイル等があるので、今回はisucon8-qualifier-standaloneで(一台構成ver)ファイルを落としてきて1と同じディレクトリにvagrantfileを置きますhttps://github.com/matsuu/vagrant-isucon3.vagrant up どん!4.vagrant up したら、vagrant sshします5.https://github.com/isucon/isucon8-qualifyここ 環境構築に書かれてることをひたすらやる6.PHPで動かしたいので初期でperlが起動しているのを停止してphpを起動sudo systemctl stop  torb.perl sudo systemctl disable torb.perl sudo systemctl start  torb.php sudo systemctl enable torb.php 7.phpでwebサイト見るためにh2oのconfファイルシンボリックリンク貼り直しと再起動sudo rm /etc/h2o/h2o.conf sudo ln -s /etc/h2o/php-h2o.conf /etc/h2o/h2o.conf sudo systemctl restart h2o 8.mariadbが起動していないので起動sudo service mariadb start 9.DBに初期データ流し込むためにシェル実行/home/isucon/torb/db/init.sh 10.vagrantfileに書いてあるIPにアクセスこれで画面が見れるはず・・・!!!!ですベンチもvagrantで実行すると初期の点数が見れるはず・・・です!!
  • テクログ

    個人的に考えるWEBサービス作成で技術的に重要だと思う要素はURLの扱いです

    URLを管理する機能が最も重要かなと思っています。 たとえば、アプリケーションのURLを管理するクラスさえあれば、パンくず、ページネーション、SQL生成の前処理、View切り替え、SEO対策、などの処理が複雑にならずに済むと感じるからです。 ルーティングの機能に各URLセグメントに名前付けが可能であれば、何かしらのID、何かしらの日付、などをセグメントの順番に関係せずに取得できますので、新たに使用するWEBフレームワークにそういった機能が無いかのチェックはしたいところです。  FuelPHPでは、routes.phpにこう書きます。正規表現を利用して数値のみを許可しています。 Controller で取得するときはこんな感じです。 debug::dumpで出力した画面です。 このブログはPythonでDjangoを使用して作成されていますが、上記と同様にセグメントに名前指定をしています。もしかすると、一般的なWEBフレームワークには備わっている機能なのかもしれません。
  • テクログ

    ブラウザテストフレームワークの5月でした

    ブラウザテストフレームワーク、使ってますか!単体テストもいいけど、やっぱりユーザが使って実際ちゃんと動作してるの?ってのが気になりますよね。最近はjsでいろいろやることも多いし、関連するところが動かなくなったり。(jsの単体テストやれって話もありますが)で、有償無償問わず、いろいろと見てみました。結構網羅したり、試したりするだけでもそれなりにかかったので、なんとなく一覧的に。・いわゆるツールでの自動テスト系teststudioRanorexAutifyTestCompleteUnified Functional TestingROBOWAREuipathkatalon studioimacros・いわゆるブラウザテストフレームワーク(E2Eテスト用)Seleniumを直使用CodeceptionCodeceptJSNightwatch.jsWebdriverIOScrapywatirAppiumSelenideGebおよびSpockCapybaraSplinterCasperJSSST (selenium-simple-test)重要視した点としては、パッとつくれて、パッと動かせる。なんだこれ、どうやるんだ、みたいなのはなし。……ということで、有償の自動テストツール系について、可能なものは体験版を入れてちょっと動かしたりしました。「ちょっと」なのはあえてちょっとだけやって、それでもできないのならば簡単じゃない!ということでした。もちろんデモや動画をみてると、「なんかすごいことやってるし、なんでもできそう…」となりますし、実際理解すればなんでもできるのかもしれません。でも少しだけいじっただけでは全く思ったとおりに動かないんですよね。というわけでツール系はなくなり、ブラウザテストフレームワークの検証となりました。テストコード書かないといけない、というのは確かに手軽とはいえないですが、サンプルがあればあとはその改良をつづけていけばなんとかなる、という思惑です。現状のサポート具合、活発さ、書きやすさ…などからCodeceptionCodeceptJSが残り、mac,PCでのブラウザテストはクリア。実機もやりたい、ということでAppium連携をしたり…ということをやっていましたよ。実機動作は結構コツが必要だったり、iPhoneだとやりたいことがどうしてもできない部分があったり…となりましたが、それ以外は結構思ったとおりのテストができましたので、毎回確認しないといけない動作がある、とか、そういった場合には役に立つのではないでしょうか。一個小ネタでいえば、テストをAWS Lambdaに連携させて、外への影響を確認したりする、ということもやってみました。純粋なE2Eテストの範疇からは外れるかとは思いますが、やはりどうしても確認したい内容もありますので、そういうものもいかがでしょう。ちなみに最終的に残ったのはCodeceptJS+Appiumでした!(以下イメージ画像
  • テクログ

    Deployerでも動的にデプロイするホストを変更したい!

    ↑ってなりますよね?なるなるーホストが固定だと、deploy.phpにホストを書いて終わり、ってなるんですけど、AWSなどで今動いてるホストがコロコロ変わるとしたらdeploy.phpには固定で書けないですね。うーんこまったどうしよう。そんなときはこれ!hosts.yml〜くわしくはこちら!https://deployer.org/docs/hosts.htmlhosts.ymlにしたがってデプロイするよってしておけば、hosts.ymlを事前に生成すれば動的にできるんだ!(deploy.phpには inventory('hosts.yml');って書けば使われるよ。まあリンク先↑に書いてある。)なんだって!すごいね!はいソース の 例。pythonのほうが楽なんだけどいじりやすいようにphpにしましたですよ?雛形(SOURCE_hosts.yml)をつくっておいて、それのIPとインスタンスIDをリプレースしてるっす。わかるっすよね。雛形はじぶんでつくってね!(リンク先参照とかテストとかして)対象EC2はタグで絞り込んだりとかもしてます。これを使ってなにかあっても責任は全く取れませんなので十分に検証してね!hosts.yml生成するだけですけど。これをjenkinsに呼ばせるなら、失敗時はexit(1);とかすれば進まないのでは。ではいいかんじのDeployerライフを。<?php require 'aws_v3.phar'; use Aws\Ec2\Ec2Client as Ec2Client; use Aws\Exception\AwsException; echo 'generate_autoscale_yml START' . PHP_EOL . PHP_EOL; /**設定箇所 開始**/ //認証情報 $auth = [         "key"   => "ああああ",         "secret" => "いいいい",         "region" => "ap-northeast-1",         "version" => "2016-11-15", ]; //タグ、AutoScaleGroupの値 $AutoScaleGroup_value = 'もがもが'; //hosts.ymlの雛形となるものを読んでおく $source_hosts_yml_string = file_get_contents('./SOURCE_hosts.yml', FILE_USE_INCLUDE_PATH); //結果ファイル名 $hosts_yml_filename = './hosts.yml'; /**設定箇所 終了**/ //hosts.ymlに結果として書き出す文字列の殻 $hosts_yml_string = ''; try{     //動いている(running)、タグが該当のインスタンスを取得     $ec2client = Ec2Client::factory($auth);     $result = $ec2client->describeInstances([             'Filters' => [                     [                             'Name' => 'tag:AutoScaleGroup',                             'Values' => [$AutoScaleGroup_value],                     ],                     [                             'Name' => 'instance-state-name',                             'Values' => ['running'],                     ],             ],             'MaxResults' => 100,     ]);     //値の分解と使用     $reservations = $result['Reservations'];     foreach ($reservations as $reservation) {         $instances = $reservation['Instances'];         foreach ($instances as $instance) {             //もととなる文字のコピー             $mod_hosts_yml_string = $source_hosts_yml_string;             //置き換えに使う文字             $InstanceId = $instance['InstanceId'];             $publicip   = '';             foreach ($instance['NetworkInterfaces'] as $networkinterface) {                 $publicip = $networkinterface['Association']['PublicIp'];             }             //[INSTANCE_ID]と[PUBLIC_IP_ADDRESS]を置き換え             $mod_hosts_yml_string = str_replace('[INSTANCE_ID]', $InstanceId, $mod_hosts_yml_string);             $mod_hosts_yml_string = str_replace('[PUBLIC_IP_ADDRESS]', $publicip, $mod_hosts_yml_string);             $hosts_yml_string .= $mod_hosts_yml_string;         }     }     //書き込み     file_put_contents($hosts_yml_filename, $hosts_yml_string); } catch(AwsException $e){     var_dump($e->getMessage());     echo 'ERROR' . PHP_EOL . PHP_EOL; } echo 'generate_autoscale_yml END' . PHP_EOL . PHP_EOL;